QMimeData类提为数据提供一个容器,用来记录关于MIME类型数据的信息
QMimeData常用来描述保存在剪切板里信息,或者拖拽原理
QMimeData对象把它所保存的信息和正确的MIME类型连接起来来保证信息可以被安全的在应用程序之间转移

,或者在同一个应用程序之间拷贝
QMimeData对象通产雇佣new来创建,并且支持QDrag和QClipboard对象,这可以使QT管理他们所使用的内存

单一的QMimeData对象可以同时用好几种不同的格式来存储同一个数据,formats()函数返回可以用的数据

格式的list,data()函数可以返回和MIME类型相连的数据类型,setData()用来为MIME类型设置数据

对于大多数MIME类型,QMimeData提供方便的函数来获取数据

例如,如果想让一个widget接受URL拖拽,可以使用下面的代码
 void MyWidget::dragEnterEvent(QDragEnterEvent *event)
 {
     if (event->mimeData()->hasUrls())
         event->acceptProposedAction();
 }

 void MyWidget::dropEvent(QDropEvent *event)
 {
     if (event->mimeData()->hasUrls()) {
         foreach (QUrl url, event->mimeData()->urls()) {
             ...
         }
     }
 }

有三种方法在QMimeData对象中来存储通常的数据
1、通常的数据可以象QByteArray()使用setData()直接存储在一个QMimeData对象中,例如
QByteArray csvData = ...;
 QMimeData *mimeData = new QMimeData;
 mimeData->setData("text/csv", csvData);
2、我们可以派生QMimeData类,继承hasFormat(),formats(),retrieveData()函数
3、如果拖拽行为发生在一个应用程序中,我们可以派生QMimeData类,并且为他添加额外的数据,
使用qobject_cast()在接受拖拽函数中,例如
  void MyWidget::dropEvent(QDropEvent *event)
     {
 const MyMimeData *myData=
          qobject_cast<const MyMimeData *>(event->mimeData());
      if (myData) {
          // access myData's data directly (not through QMimeData's API)

     }


拖放 Drag and Drop,有时又被称为 DnD,是现代软件开发中必不可少的一项技术。它提供了一种能够在应用程序内部甚至是应用程序之间进行信息交换的机制,并且,操作系统与应用程序之间进行剪贴板的内容交换,也可以被认为是 DnD 的一部分。
DnD 其实是由两部分组成的:Drag 和 Drop。Drag 是将被拖放对象“拖动”,Drop 是将被拖放对象“放下”,前者一般是一个按下鼠标的过程,而后者则是一个松开鼠标的过程,这两者之间鼠标一直是被按下的。当然,这只是一种通常的情况,其他情况还是要看应用程序的具体实现。对于 Qt 而言,widget既可以作为 drag 对象,也可以作为 drop 对象,或者二者都是。
下面的一个例子来自 C++ GUI Programming with Qt 4, 2nd Edition。在这个例子中,我们创建一个程序,可以将系统中的文本文件拖放过来,然后在窗口中读取内容。
mainwindow.h
  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.  
  4. #include <QtGui>  
  5.  
  6. class MainWindow : public QMainWindow  
  7. {  
  8.     Q_OBJECT  
  9.  
  10. public:  
  11.     MainWindow(QWidget *parent = 0);  
  12.     ~MainWindow();  
  13.  
  14. protected:  
  15.     void dragEnterEvent(QDragEnterEvent *event);  
  16.     void dropEvent(QDropEvent *event);  
  17.  
  18. private:  
  19.     bool readFile(const QString &fileName);  
  20.     QTextEdit *textEdit;  
  21. };  
  22.  
  23. #endif // MAINWINDOW_H 
mainwindow.cpp
  1. #include "mainwindow.h"  
  2.  
  3. MainWindow::MainWindow(QWidget *parent)  
  4.     : QMainWindow(parent)  
  5. {  
  6.     textEdit = new QTextEdit;  
  7.     setCentralWidget(textEdit);  
  8.  
  9.     textEdit->setAcceptDrops(false);   //关闭QTextEdit的拖放接收
  10.     setAcceptDrops(true);   //打开主窗口的拖放接收
  11.  
  12.     setWindowTitle(tr("Text Editor"));  
  13. }  
  14.  
  15. MainWindow::~MainWindow()  
  16. {  
  17. }  
  18.  
  19. void MainWindow::dragEnterEvent(QDragEnterEvent *event)  
  20. {  
  21.     if (event->mimeData()->hasFormat("text/uri-list")) {   //检测事件的mimeData
  22.         event->acceptProposedAction();  
  23.     }  
  24. }  
  25.  
  26. void MainWindow::dropEvent(QDropEvent *event)  
  27. {  
  28.     QList<QUrl> urls = event->mimeData()->urls();  
  29.     if (urls.isEmpty()) {  
  30.         return;  
  31.     }  
  32.  
  33.     QString fileName = urls.first().toLocalFile();  
  34.     if (fileName.isEmpty()) {  
  35.         return;  
  36.     }  
  37.  
  38.     if (readFile(fileName)) {  
  39.         setWindowTitle(tr("%1 - %2").arg(fileName, tr("Drag File")));  
  40.     }  
  41. }  
  42.  
  43. bool MainWindow::readFile(const QString &fileName)  
  44. {  
  45.     bool r = false;  
  46.     QFile file(fileName);  
  47.     QTextStream in(&file);  
  48.     if(file.open(QIODevice::ReadOnly|QFile::Text)) {  
  49.         textEdit->setText(in.ReadAll());  
  50. r=true;
  51.     }  
  52.         return r;  
main.cpp
  1. #include <QtGui/QApplication>  
  2. #include "mainwindow.h"  
  3.  
  4. int main(int argc, char *argv[])  
  5. {  
  6.     QApplication a(argc, argv);  
  7.     MainWindow w;  
  8.     w.show();  
  9.     return a.exec();  
这里的代码并不是很复杂。在MainWindow中,一个QTextEdit作为窗口中间的widget。这个类中有两个protected的函数: dragEnterEvent() 和 dropEvent(),这两个函数都是继承自 QWidget,看它们的名字就知道这是两个事件,而不仅仅是signal。
在构造函数中,我们创建了 QTextEdit 的对象。默认情况下,QTextEdit 可以接受从其他的应用程序拖放过来的文本类型的信息。如果用户把一个文件拖到这里面,那么就会把文件名插入到文本的当前位置。但是我们希望让MainWindow 读取文件内容,而不仅仅是插入文件名,所以我们在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 的一个list。通常,这种拖动应该只用一个文件,但是也不排除多个文件一起拖动。因此我们需要检查这个list是否为空,如果不为空,则取出第一个。如果不成立,则立即返回。最后我们调用 readFile() 函数读取文件内容。关于读取操作我们会在以后的章节中详细说明,这里不再赘述。
好了,至此我们的小程序就解释完毕了,运行一下看看效果吧!
对于拖动和脱离,Qt 也提供了类似的函数: dragMoveEvent() 和 dragLeaveEvent(),不过对于大部分应用而言,这两个函数的使用率要小得多。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐