Qt学習の道(52):ドラッグアンドドロップ技術の一つ
ドラッグアンドドロップDrag and Dropは、DnDとも呼ばれることもあり、現代のソフトウェア開発に欠かせない技術です.これにより、アプリケーション内部、さらにはアプリケーション間で情報交換が可能となるメカニズムが提供され、オペレーティングシステムとアプリケーション間でクリップボードのコンテンツ交換が行われ、DnDの一部と考えられてもよい.
DnDは実は2つの部分から構成されています:DragとDrop.Dragはドラッグアンドドロップされるオブジェクトを「ドラッグ」し、Dropはドラッグアンドドロップされるオブジェクトを「ドロップ」し、前者は一般的にマウスを押すプロセスであり、後者はマウスを離すプロセスであり、両者の間でマウスはずっと押されている.もちろん、これは通常の状況にすぎませんが、他の状況はアプリケーションの具体的な実装によって異なります.Qtの場合、widgetはdragオブジェクトとしてもdropオブジェクトとしても、どちらでもよい.
次の例はC++GUI Programming with Qt 4,2 nd Editionから来ている.この例では、システム内のテキストファイルをドラッグ&ドロップし、ウィンドウでコンテンツを読み込むプログラムを作成します.
mainwindow.h
mainwindow.cpp
main.cpp
ここのコードは複雑ではありません.MainWindowでは、ウィンドウの中央にあるwidgetとしてQTextEditが使用されます.このクラスには2つのprotectedの関数があります.dragEnterEvent()とdropEvent()です.この2つの関数はQWidgetから継承されています.名前を見るとsignalだけでなく、2つのイベントであることがわかります.
コンストラクション関数ではQTextEditのオブジェクトを作成しました.デフォルトでは、QTextEditは他のアプリケーションからドラッグ&ドロップしたテキストタイプの情報を受け入れることができます.ユーザーがファイルをここにドラッグすると、ファイル名がテキストの現在の位置に挿入されます.ただし、ファイル名を挿入するだけでなく、MainWindowでdropイベントを処理したいので、QTextEditのsetAcceptDrops()関数をfalseに設定し、MainWindowのsetAcceptDrops()をtrueに設定して、MainWindowでdropイベントを処理します.
ユーザーがコンポーネントの上にオブジェクトをドラッグすると、dragEnterEvent()関数がコールバックされます.イベント処理コードでacceptProposeAction()関数を呼び出すと、ドラッグしたオブジェクトをこのコンポーネントに置くことができることをユーザーに示すことができます.既定では、コンポーネントはドラッグ&ドロップを受け入れません.このような関数を呼び出すと、Qtは自動的にカーソルでコンポーネントにオブジェクトを置くことができるかどうかをユーザーに提示します.ここでは、ウィンドウがドラッグ&ドロップを受け入れることができることをユーザーに伝えたいと思います.そこで、まずドラッグアンドドロップのMIMEタイプをチェックします.MIMEタイプはtext/uri-listであり、通常、URIのリストを記述するために使用される.これらのURIは、ファイル名であってもよいし、URLであってもよいし、他のリソース記述子であってもよい.MIMEタイプはInternet Assigned Numbers Authority(IANA)によって定義され、Qtのドラッグ・アンド・ドロップ・イベントはMIMEタイプを使用してドラッグ・アンド・ドロップ・オブジェクトのタイプを判断します.MIMEタイプの詳細については、「http://www.iana.org/assignments/media-types/.
ユーザーがコンポーネントの上にオブジェクトを解放すると、dropEvent()関数がコールバックされます.QMimeData::urls()またはQurlのリストを使用します.通常、このドラッグは1つのファイルだけを使用する必要がありますが、複数のファイルを一緒にドラッグすることも排除されません.したがって、このlistが空であるかどうかを確認し、空でない場合は最初のリストを取り出します.成立しない場合は、すぐに戻ります.最後にreadFile()関数を呼び出してファイルの内容を読み込みます.読み出し操作については後述するが,ここでは省略する.
では、これで私たちの小さなプログラムの説明が終わりました.実行して効果を見てみましょう.
Qtは、ドラッグおよび離脱についても同様の関数を提供します.dragMoveEvent()とdragLeaveEvent()ですが、ほとんどのアプリケーションでは、この2つの関数の使用率はずっと小さいです.
DnDは実は2つの部分から構成されています:DragとDrop.Dragはドラッグアンドドロップされるオブジェクトを「ドラッグ」し、Dropはドラッグアンドドロップされるオブジェクトを「ドロップ」し、前者は一般的にマウスを押すプロセスであり、後者はマウスを離すプロセスであり、両者の間でマウスはずっと押されている.もちろん、これは通常の状況にすぎませんが、他の状況はアプリケーションの具体的な実装によって異なります.Qtの場合、widgetはdragオブジェクトとしてもdropオブジェクトとしても、どちらでもよい.
次の例はC++GUI Programming with Qt 4,2 nd Editionから来ている.この例では、システム内のテキストファイルをドラッグ&ドロップし、ウィンドウでコンテンツを読み込むプログラムを作成します.
mainwindow.h
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
-
- #include <QtGui>
-
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
-
- public:
- MainWindow(QWidget *parent = 0);
- ~MainWindow();
-
- protected:
- void dragEnterEvent(QDragEnterEvent *event);
- void dropEvent(QDropEvent *event);
-
- private:
- bool readFile(const QString &fileName);
- QTextEdit *textEdit;
- };
-
- #endif // MAINWINDOW_H
mainwindow.cpp
- #include "mainwindow.h"
-
- MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent)
- {
- textEdit = new QTextEdit;
- setCentralWidget(textEdit);
-
- textEdit->setAcceptDrops(false);
- setAcceptDrops(true);
-
- setWindowTitle(tr("Text Editor"));
- }
-
- MainWindow::~MainWindow()
- {
- }
-
- void MainWindow::dragEnterEvent(QDragEnterEvent *event)
- {
- if (event->mimeData()->hasFormat("text/uri-list")) {
- event->acceptProposedAction();
- }
- }
-
- void MainWindow::dropEvent(QDropEvent *event)
- {
- QList<QUrl> urls = event->mimeData()->urls();
- if (urls.isEmpty()) {
- return;
- }
-
- QString fileName = urls.first().toLocalFile();
- if (fileName.isEmpty()) {
- return;
- }
-
- if (readFile(fileName)) {
- setWindowTitle(tr("%1 - %2").arg(fileName, tr("Drag File")));
- }
- }
-
- bool MainWindow::readFile(const QString &fileName)
- {
- bool r = false;
- QFile file(fileName);
- QTextStream in(&file);
- QString content;
- if(file.open(QIODevice::ReadOnly)) {
- in >> content;
- r = true;
- }
- textEdit->setText(content);
- return r;
- }
main.cpp
- #include <QtGui/QApplication>
- #include "mainwindow.h"
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- MainWindow w;
- w.show();
- return a.exec();
- }
ここのコードは複雑ではありません.MainWindowでは、ウィンドウの中央にあるwidgetとしてQTextEditが使用されます.このクラスには2つのprotectedの関数があります.dragEnterEvent()とdropEvent()です.この2つの関数はQWidgetから継承されています.名前を見るとsignalだけでなく、2つのイベントであることがわかります.
コンストラクション関数ではQTextEditのオブジェクトを作成しました.デフォルトでは、QTextEditは他のアプリケーションからドラッグ&ドロップしたテキストタイプの情報を受け入れることができます.ユーザーがファイルをここにドラッグすると、ファイル名がテキストの現在の位置に挿入されます.ただし、ファイル名を挿入するだけでなく、MainWindowでdropイベントを処理したいので、QTextEditのsetAcceptDrops()関数をfalseに設定し、MainWindowのsetAcceptDrops()をtrueに設定して、MainWindowでdropイベントを処理します.
ユーザーがコンポーネントの上にオブジェクトをドラッグすると、dragEnterEvent()関数がコールバックされます.イベント処理コードでacceptProposeAction()関数を呼び出すと、ドラッグしたオブジェクトをこのコンポーネントに置くことができることをユーザーに示すことができます.既定では、コンポーネントはドラッグ&ドロップを受け入れません.このような関数を呼び出すと、Qtは自動的にカーソルでコンポーネントにオブジェクトを置くことができるかどうかをユーザーに提示します.ここでは、ウィンドウがドラッグ&ドロップを受け入れることができることをユーザーに伝えたいと思います.そこで、まずドラッグアンドドロップのMIMEタイプをチェックします.MIMEタイプはtext/uri-listであり、通常、URIのリストを記述するために使用される.これらのURIは、ファイル名であってもよいし、URLであってもよいし、他のリソース記述子であってもよい.MIMEタイプはInternet Assigned Numbers Authority(IANA)によって定義され、Qtのドラッグ・アンド・ドロップ・イベントはMIMEタイプを使用してドラッグ・アンド・ドロップ・オブジェクトのタイプを判断します.MIMEタイプの詳細については、「http://www.iana.org/assignments/media-types/.
ユーザーがコンポーネントの上にオブジェクトを解放すると、dropEvent()関数がコールバックされます.QMimeData::urls()またはQurlのリストを使用します.通常、このドラッグは1つのファイルだけを使用する必要がありますが、複数のファイルを一緒にドラッグすることも排除されません.したがって、このlistが空であるかどうかを確認し、空でない場合は最初のリストを取り出します.成立しない場合は、すぐに戻ります.最後にreadFile()関数を呼び出してファイルの内容を読み込みます.読み出し操作については後述するが,ここでは省略する.
では、これで私たちの小さなプログラムの説明が終わりました.実行して効果を見てみましょう.
Qtは、ドラッグおよび離脱についても同様の関数を提供します.dragMoveEvent()とdragLeaveEvent()ですが、ほとんどのアプリケーションでは、この2つの関数の使用率はずっと小さいです.