拖放提供一个应用程序之间传递信息的一种简单的可视化机制。拖放机制类似于剪切和粘贴机制。拖放操作同时被QT项目视图和图形视图框架支持。
QApplication提供了两个拖放相关的方法:
1. QApplication::startDragTime。它描述了用户按下鼠标多长时间开始拖放操作。
2. QApplication::startDragDistance。它描述了用户按下鼠标移动多少像素才开始拖动。默认的是4个像素。
拖动操作drag:
为了开始一个拖动操作,需要创建一个QDrag对象,然后调用exec()函数。通常,在鼠标左键按下后并光标被移动了一定距离我们就开始一个拖动操作是个好主意,但是一个最简单的方式是,让一个重新实现了mousePressEvent()的窗口部件允许它拖动,然后开始拖放操作。例如:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton
&& iconLabel->geometry().contains(event->pos())) {
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setText(commentEdit->toPlainText());
drag->setMimeData(mimeData);
drag->setPixmap(iconPixmap);
Qt::DropAction dropAction = drag->exec();
...
}
}
QMimeData是记录MIME类型信息的类,标准的MIME类型是有国际因特网地址分配委员会定义的,由类型,子类型信息和分隔两者的斜线组成。MIME通常由剪贴板和拖放系统使用。QMimeData提供了一些可以用于处理最常见的拖动信息(例如图像,URL,颜色,纯文本,超文本)。setText()设置文本信息。将QMimeData对象存储在QDrag对象里,并设置了随光标移动的拖动图片setPixmap()。QDrag::exec()启动拖动操作。
通常我们要辨别点击和拖动事件,那么要利用鼠标按下事件来获取初始位置,再在鼠标移动事件里辨别是否响应拖动。
void DragWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
dragStartPosition = event->pos();
}
void DragWidget::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
if ((event->pos() - dragStartPosition).manhattanLength()
< QApplication::startDragDistance())
return;
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setData(mimeType, data);
drag->setMimeData(mimeData);
Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
...
}
鼠标移动事件响应函数里manhattanLength()是曼哈顿长度,也就是鼠标按下到移动到当前光标位置的粗略长度值。startDragDistance()是先前提到的开始拖动距离默认是4像素。设置这样的判断可以过滤掉一些诸如点击鼠标后不小心抖动的失误操作。
放置操作drop:
为了接受一个放置操作,我们要为窗口部件调用setAcceptDrops(true)。并重实现dragEnterEvent()和dropEvent()事件处理函数。
例如,下面代码为QWidget子类实现放置操作代码:
Window::Window(QWidget *parent)
: QWidget(parent)
{
...
setAcceptDrops(true);
}
void Window::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("text/plain"))
event->acceptProposedAction();
}
这里hasFormat通知只处理”text/plain”格式事件,acceptProposedAction通知接收目的活动,表明可以在这个部件上拖放对象。
void Window::dropEvent(QDropEvent *event)
{
textBrowser->setPlainText(event->mimeData()->text());
mimeTypeCombo->clear();
mimeTypeCombo->addItems(event->mimeData()->formats());
event->acceptProposedAction();
}
当将目标对象拖动放置到我们的这个Window窗口部件时,textBrowser设置文本,将之前保存的文本信息输入到其中。清空mimeTypeCombo并添加一项。
我们可能会要忽略目的动作(action),而是执行一个我们需要的其他动作。这时,我们需要调用setDropAction(),并附上我们需要的Qt::DropAction类型,再调用accept()。例如:
event->setDropAction(Qt::MoveAction);
event->accept();
在一些更为复杂的程序中,重新实现dragMoveEvent(),dragLeaveEvent()事件响应函数,让你的部件可以响应对鼠标放置和离开事件。不过大多数部件都已经为我们实现好了。
下面给出一个实例,这是C++ GUI QT4 编程 的例子。我截取重要的部分。
定义一个ProjectListWidget 类,为它实现拖动和放置操作。
class ProjectListWidget : public QListWidget
{
Q_OBJECT
public:
ProjectListWidget(QWidget *parent = 0);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private:
void performDrag();
QPoint startPos;
};
ProjectListWidget::ProjectListWidget(QWidget *parent)
: QListWidget(parent)
{
setAcceptDrops(true);
}
void ProjectListWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
startPos = event->pos();
QListWidget::mousePressEvent(event);
}
void ProjectListWidget::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
int distance = (event->pos() - startPos).manhattanLength();
if (distance >= QApplication::startDragDistance())
performDrag();
}
QListWidget::mouseMoveEvent(event);
}
// 判定是否来自同一个对象的放置,对来自不同对象的进行处理
// 一下几个都是同理
void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event)
{
ProjectListWidget *source =
qobject_cast
if (source && source != this) {
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
// 接收鼠标移动动作
void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event)
{
ProjectListWidget *source =
qobject_cast
if (source && source != this) {
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
// 接收放置后添加一项
void ProjectListWidget::dropEvent(QDropEvent *event)
{
ProjectListWidget *source =
qobject_cast
if (source && source != this) {
addItem(event->mimeData()->text());
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
// 实现拖动
void ProjectListWidget::performDrag()
{
QListWidgetItem *item = currentItem();
if (item) {
QMimeData *mimeData = new QMimeData;
mimeData->setText(item->text());
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(QPixmap(":/images/person.png"));
if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
delete item;
}
}