原文地址:http://devbean.blog.51cto.com/448512/280052
一 基本概念
拖放 Drag and Drop( DnD):提供了一种能够在应用程序内部甚至是应用程序之间进行信息交换的机制,并且,操作系统与应用程序之间进行剪贴板的内容交换,也可以被认为是 DnD 的一部分。
(1)DnD 由两部分组成的:Drag 和 Drop。
Drag 是将被拖放对象“拖动”,Drop 是将被拖放对象“放下”,Drag是一个按下鼠标的过程,而Drop是一个松开鼠标的过程,这两者之间鼠标一直是被按下的。
这只是一种通常的情况,其他情况还是要看应用程序的具体实现。对于 Qt 而言,widget既可以作为 drag 对象,也可以作为 drop 对象,或者二者都是。
二 代码
功能需求:
创建一个程序
可以将系统中的文本文件拖放过来,并且在窗口中读取内容
1.所有代码
(1)mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QTextEdit>
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
(2)mainwindow.cpp
#include "mainwindow.h"
#include<QDragEnterEvent>
#include<QDropEvent>
#include<QList>
#include <QMimeData>
#include<QTextStream>
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;
}
(3)main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
2.运行结果
没有txt文件之前
拖入txt文件之后
三. 代码解释
1.
(1)
mainwindow.cpp
textEdit = new QTextEdit;
setCentralWidget(textEdit);
一个QTextEdit作为窗口中间的widget。
(2)
mainwindow.h
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
这个类中有两个protected的函数:dragEnterEvent() 和 dropEvent(),这两个函数都是继承自 QWidget,看它们的名字就知道这是两个事件,而不仅仅是signal。
(3)
mainwindow.h
QTextEdit *textEdit;
我们创建了 QTextEdit 的对象。
默认情况下,QTextEdit 可以接受从其他的应用程序拖放过来的文本类型的信息。
如果用户把一个文件拖到这里面,那么就会把文件名插入到文本的当前位置。
2.
textEdit->setAcceptDrops(false);
setAcceptDrops(true);
在本程序中的功能要求为:让MainWindow 读取文件内容,而不仅仅是插入文件名.
我们在MainWindow中对 drop 事件进行了处理,因此要把QTextEdit的setAcceptDrops()函数置为false,并且把MainWindow的setAcceptDrops()置为true,以便让MainWindow对 drop 事件进行处理。
3.
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("text/uri-list")) {
event->acceptProposedAction();
}
}
(1)用户将对象拖动到组件上面时,dragEnterEvent()函数会被回调。
(2)在事件处理代码中调用 acceptProposeAction() 函数,我们就可以向用户暗示,你可以将拖动的对象放在这个组件上。
默认情况下,组件是不会接受拖放的。如果我们调用了acceptProposeAction函数,那么Qt会自动地以光标来提示用户是否可以将对象放在组件上。
(3)此模块中,窗口可以接受拖放。
所以检查拖放的MIME类型
MIME类型为 text/uri-list 通常用来描述一个 URI 的列表。这些 URI 可以是文件名,可以是 URL或者其他的资源描述符。MIME类型由 Internet Assigned Numbers Authority (IANA) 定义,Qt 的拖放事件使用MIME类型来判断拖放对象的类型。关于 MIME类型的详细信息,请参考 http://www.iana.org/assignments/media-types/.
4.
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")));
}
}
(1)当用户将对象释放到组件上面时,dropEvent() 函数会被回调。
(2)我们使用 QMimeData::urls()来获取 QUrl 的一个list。通常,这种拖动应该只用一个文件,但是也不排除多个文件一起拖动。
(3)我们需要检查这个list是否为空
urls.isEmpty()
如果不为空,则取出第一个
QString fileName = urls.first().toLocalFile();
如果不成立,则立即返回。
if (urls.isEmpty()) {
return;
}
最后我们调用 readFile() 函数读取文件内容。
readFile(fileName)