Qt でドラッグアイテムを受取る方法
今回は前回作成した
をベースに、ちょっと便利な機能を追加します。
アプリで扱うファイルは、通常ファイルダイアログなどを通じて取得します。
ファイルを開く場合、ファイルダイアログの他Nautilusなどのアプリからのドラッグ&ドロップ経由でも扱えると便利なケースが多々あります (^o^)v
そこで、今回はドラッグ&ドロップ経由でもXSPFファイルを開けるように改良します。
実際の動作を動画にて...
組み込み方
(1)ドロップ許可を与えます。
setAcceptDrops(true);
を使います。
(2)ドラッグ通知時にドロップ可能な判断します。
以下の関数でドラッグメッセージを受け取り、ドロップ可能などうか判断します。
void dragEnterEvent(QDragEnterEvent *e);
関数内で
e->mimeData()
が受取可能な mime か判断します。
hasText() = text/plain
hasHtml() = text/html
hasUrls() = text/uri-list
hasImage() = image/ *
hasColor() = application/x-color
の5種類です。
受取可能なものであれば、
acceptProposedAction();
で許可を与えます。
許可すると、ドラッグ中のマウスカーソルの形状も変化します。
こんな感じのマウスカーソルです (^^♪
(3)ドロップ通知時に対応した処理を行います。
以下の関数でドロップメッセージを受け取り、ドロップ時の処理を行います。
void dropEvent(QDropEvent *e);
時間がかかるような処理の場合、別のメッセージなどを発生させ、ドロップスレッドを開放させます。
今回は、処理が短時間で済むので、そのままファイルのオープン処理を行っています。
今回もメインウィンドウのクラスソースとヘッダーだけ張り付けます。
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtWidgets> #include <QStandardPaths> #include <QFileDialog> #include <QDomDocument> #include "aboutdialog.h" #include "appinitdata.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: // menus void on_action_Open_triggered(); void on_action_Quit_triggered(); void on_action_Save_triggered(); void on_action_SaveAS_triggered(); void on_action_New_triggered(); void on_action_About_triggered(); private: Ui::MainWindow *ui; QLabel *label_MessageBar_normal = new QLabel; // application init-data appInitData appInit; // XML tree QDomDocument domDocument; QString editing_Filepath; int m_nTrack_cnt; void open_PlayLlist_file(QString filename); void XML_tree_open(); bool XML_tree_read(QIODevice *device); void parsePlaylistElement(QTreeWidgetItem *ptree_item,const QDomElement &root); void parseTrackElement(QTreeWidgetItem *ptree_track, const QDomElement &element); protected: void dragEnterEvent(QDragEnterEvent *e); void dropEvent(QDropEvent *e); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // get init appInit.m_byteArray_name = "treeWidget_playlist"; appInit.get_appInitDatas(this->window(), "MAIN"); // setting status bar ui->statusBar->addWidget(label_MessageBar_normal); label_MessageBar_normal->setText(tr("File not selected")); // setting treeWidget_playlist QStringList list_label; list_label << tr("tag") << tr("value"); ui->treeWidget_playlist->header()->setSectionResizeMode(QHeaderView::Interactive); ui->treeWidget_playlist->setHeaderLabels(list_label); if (appInit.m_bbyteArray) ui->treeWidget_playlist->header()->restoreState(appInit.m_byteArray); // etc init editing_Filepath = appInit.m_sLastopenPath; // accept drop setAcceptDrops(true); } MainWindow::~MainWindow() { // set init appInit.m_byteArray_name = "treeWidget_playlist"; appInit.m_byteArray = ui->treeWidget_playlist->header()->saveState(); appInit.m_bbyteArray = true; if (editing_Filepath.length() == 0) appInit.m_sLastopenPath = ""; else{ QFileInfo fi = QFileInfo(editing_Filepath); if (fi.isFile()) appInit.m_sLastopenPath = QFileInfo(editing_Filepath).path(); else appInit.m_sLastopenPath = editing_Filepath; } appInit.set_appInitDatas(this->window(), "MAIN"); delete ui; } /* Menu actions */ void MainWindow::on_action_Quit_triggered() { this->close(); } void MainWindow::on_action_Open_triggered() { QString init_path; if (editing_Filepath.length() > 3){ QFileInfo fi = QFileInfo(editing_Filepath); if (fi.isFile()) init_path = QFileInfo(editing_Filepath).path(); else init_path = editing_Filepath; } else init_path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)[0]; QString filename = QFileDialog::getOpenFileName( this, tr("Open Playlist file"), init_path, tr("Playlist File (*.xspf);;ALL file (*.*)")); if (filename.length()==0){ this->statusBar()->showMessage(tr("select : Canseled"),3000); return; } } void MainWindow::open_PlayLlist_file(QString filename) { editing_Filepath = filename; label_MessageBar_normal->setText(editing_Filepath); this->statusBar()->showMessage(tr("select : ")+filename,3000); XML_tree_open(); label_MessageBar_normal->setText( QString::number(m_nTrack_cnt)+" tracks << "+editing_Filepath); } void MainWindow::on_action_Save_triggered() { } void MainWindow::on_action_SaveAS_triggered() { } void MainWindow::on_action_New_triggered() { } void MainWindow::on_action_About_triggered() { aboutDialog *pdialog = new aboutDialog(this); pdialog->exec(); delete pdialog; } /************************************************************/ /* functions */ void MainWindow::XML_tree_open() { ui->treeWidget_playlist->clear(); QFile file(editing_Filepath); if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning(this, tr("PLeditor"), tr("Cannot read file %1:\n%2.") .arg(editing_Filepath) .arg(file.errorString())); this->statusBar()->showMessage(tr("Cannot open file : ")+editing_Filepath, 3000); return; } XML_tree_read(&file); } bool MainWindow::XML_tree_read(QIODevice *device) { QString errorStr; int errorLine; int errorColumn; if (!domDocument.setContent( device, true, &errorStr, &errorLine,&errorColumn)) { QMessageBox::information(window(), tr("PLeditor"), tr("Parse error at line %1, column %2:\n%3") .arg(errorLine) .arg(errorColumn) .arg(errorStr)); this->statusBar()->showMessage( tr("Parse error in file : ")+editing_Filepath, 3000); return false; } QDomElement root = domDocument.documentElement(); if (root.tagName() != "playlist") { QMessageBox::information(window(), tr("PLeditor"), tr("The file is not an playlist file.")); this->statusBar()->showMessage( tr("not an playlist : ")+editing_Filepath, 3000); return false; } else if (root.hasAttribute("version") && root.attribute("version") != "1") { QMessageBox::information(window(), tr("PLeditor"), tr("The file is not an playlist version 1 " "file.")); this->statusBar()->showMessage( tr("not an playlist version: ")+editing_Filepath, 3000); return false; } QStringList liststr; QDomNamedNodeMap attrMap = root.attributes(); liststr << "playlist "+attrMap.item(0).toAttr().name() << attrMap.item(0).toAttr().value(); QTreeWidgetItem *ptree_item = new QTreeWidgetItem(liststr, 0); ptree_item->setToolTip(0,tr("attibute in playlist")); ui->treeWidget_playlist->addTopLevelItem(ptree_item); // playlist attribute int attrCount = attrMap.length(); for(int i = 0; i < attrCount; ++i){ QDomAttr attr = attrMap.item(i).toAttr(); } // in playlist-tag parsePlaylistElement(ptree_item,root); // in tracklist m_nTrack_cnt = 0; // Loops in a track list QDomElement child = root.firstChildElement("trackList"); while (!child.isNull()) { liststr.clear(); liststr << "<tracklist>" << ""; QTreeWidgetItem *ptree_item_tracklist = new QTreeWidgetItem(liststr, 0); ptree_item_tracklist->setToolTip(0,tr("tracklist")); ptree_item->addChild(ptree_item_tracklist); // Loops in a track QDomElement child2 = child.firstChildElement("track"); while (!child2.isNull()) { liststr.clear(); liststr << "<track>" << ""; QTreeWidgetItem *ptree_item_track = new QTreeWidgetItem(liststr, 0); ptree_item_track->setToolTip(0,tr("track")); ptree_item_tracklist->addChild(ptree_item_track); // in track parseTrackElement(ptree_item_track,child2); m_nTrack_cnt++; child2 = child2.nextSiblingElement("track"); } child = child.nextSiblingElement("tracklist"); } ui->treeWidget_playlist->expandAll(); if (m_nTrack_cnt == 0){ this->statusBar()->showMessage( tr("Track was not found : ")+editing_Filepath, 10000); } else { this->statusBar()->showMessage( QString::number(m_nTrack_cnt)+tr(" tracks found : ")+editing_Filepath, 10000); } return true; } // Elements other than track list void MainWindow::parsePlaylistElement(QTreeWidgetItem *ptree_playlist,const QDomElement &root) { QStringList liststr; QDomNode node = root.firstChild(); while (!node.isNull()) { if (node.isElement()) { QDomElement element = node.toElement(); if (element.tagName() != "trackList"){ liststr.clear(); liststr << element.tagName() << element.text(); QTreeWidgetItem *ptree_playlist_element = new QTreeWidgetItem(liststr, 0); ptree_playlist_element->setFlags(Qt::ItemIsEditable|Qt::ItemIsEnabled); ptree_playlist->addChild(ptree_playlist_element); } } node = node.nextSibling(); } } // Elements in a track void MainWindow::parseTrackElement(QTreeWidgetItem *ptree_track,const QDomElement &element) { QStringList liststr; QDomElement child = element.firstChildElement(); while (!child.isNull()) { QString tag_name = child.tagName(); QString value = child.text(); QString str= tag_name+","+value; liststr.clear(); liststr << tag_name << value; QTreeWidgetItem *ptree_track_item = new QTreeWidgetItem(liststr, 0); ptree_track_item->setFlags(Qt::ItemIsEditable|Qt::ItemIsEnabled); ptree_track->addChild(ptree_track_item); child = child.nextSiblingElement(); } } /************************************************************ drag & drop xspf-file ************************************************************/ void MainWindow::dragEnterEvent(QDragEnterEvent *e) { if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); } } void MainWindow::dropEvent(QDropEvent *e) { if (e->mimeData()->hasUrls()) { QString suffix = QFileInfo(e->mimeData()->text().trimmed()).suffix(); if (suffix.toLower() == "xspf"){ open_PlayLlist_file(QUrl(e->mimeData()->text().trimmed()).toLocalFile()); } } }
他のクラスファイルやリソースファイルなどはZIPファイルをダウンロードして確認してください。
ZIP-file (51KB) download from Google DRIVE
空いた時間を見つけながら作成しているので、バグ等があってもご愛嬌でお願いします。(簡単なデバックと動作テストしかしていません)
今回は表示だけですが、最終的にはエディターとなる予定です (^^♪
また、区切りの良いタイミングで公開しますので、気長にお待ちくださいw
「Qt Quick」アプリケーション開発 (I・O BOOKS)
- 作者: 村上信昌,吉川武宏
- 出版社/メーカー: 工学社
- 発売日: 2018/10/01
- メディア: 単行本
- この商品を含むブログを見る
Qtプログラミング入門―使いやすいフレームワークを基礎から解説 (I・O BOOKS)
- 作者: 津田伸秀
- 出版社/メーカー: 工学社
- 発売日: 2011/12/01
- メディア: 単行本
- 購入: 1人 クリック: 4回
- この商品を含むブログ (9件) を見る
PythonでGUIをつくろう─はじめてのQt for Python (技術書典シリーズ(NextPublishing))
- 作者: 浅野一雄
- 出版社/メーカー: インプレスR&D
- 発売日: 2019/01/18
- メディア: オンデマンド (ペーパーバック)
- この商品を含むブログを見る
- 作者: 理音伊織
- 発売日: 2018/10/08
- メディア: Kindle版
- この商品を含むブログを見る