实现Drag and Drop的最简模型

在做图形界面时,我们经常会遇到需要实现Drag & Drop的效果,即拖拽效果,例如在实现拼图游戏的时候,我们就需要能够用鼠标拖拽拼图块,然后在我们想要停下的地方松开鼠标左键,从而将该图块放置在我们指定的地方。
Qt对拖拽的支持是非常强大和全面的,但是无论是Qt自身所带的Demo还是网上的相关资料,都感觉复杂了,太多和Drag & Drop无必需联系的细节掩盖了改效果的实现主线。下面我实现了一个Drag & Drop效果的最简模型。
程序运行效果是,在对话框中会出现一只可爱的企鹅(item),然后可以通过鼠标左键对该企鹅进行拖拽(Drag & Drop)。
首先,我们需要从QLabel继承一个我们自己的类DragItem。之所以选择QLabel是因为该类比较基本,而且能够很好的、无边框得存在于对话框中。实现该类最重要的也是必须的一点是,要在其构造函数中创建一个QImage对象,然后通过setPixmap函数将其选入,代码如下:
DragItem::DragItem(QWidget *parent):QLabel(parent)
{
  QImage image (128, 128, QImage::Format_ARGB32);
  if (image.load("../icon.png") == false)
      QMessageBox::warning(this, "ERROR", "Load image error!");
  setPixmap (QPixmap::fromImage(image));
}
然后,我们还需要一个对话框用于显示该item,也就是起到容器的作用。该对话框类必须要在其构造函数中通过setAcceptDrops函数,将其AcceptDrops属性设置为true,否则无法进行拖拽。构造函数如下:
Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog)
{
DragItem *item = new DragItem (this);
item->setAttribute(Qt::WA_DeleteOnClose);
item->show();
setMinimumSize (400, 400);
setWindowTitle (tr("Drag & Drop Simplest Demo"));
setAcceptDrops (true);
ui->setupUi(this);
}
然后关键就是实现三个事件响应函数,分别是:
void dragEnterEvent (QDragEnterEvent *event);
void dropEvent (QDropEvent *event);
void mousePressEvent (QMouseEvent *event);
dragEnterEvent函数在鼠标拖拽物件进入该对话框范围内是被触发;dropEvent是当用户在对话框范围内松开鼠标左键结束拖拽时被触发;mousePressEvent,顾名思义,就是当鼠标被按下(无论是左键、右键还是中轮)被触发。我们需要在mousePressEvent响应函数内,创建QMimeData数据对象,然后用QDrag实现最终的拖拽效果。mousePressEvent负责对传入的QMimeData进行辨析,如果是我们想要的拖拽文件类型,就接受这个拖拽信息,否则予以忽略。dropEvent要做的是当拖拽结束,我们需要在新的位置再创建一个item对象,而将原先位置的item删除(或者关闭),通知完全将原有的item属性复制到新创建的item对象中。
这三个函数的实现代码如下:
void Dialog::dragEnterEvent (QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("application/x-draganddrop"))
    event->accept();
else
    event->ignore();
}

void Dialog::dropEvent (QDropEvent *event)
{
if (event->mimeData()->hasFormat("application/x-draganddrop"))
{
    const QMimeData *mimeData = event->mimeData();
    QByteArray exData = mimeData->data("application/x-draganddrop");
    QDataStream dataStream (&exData, QIODevice::ReadOnly);
    QPoint pos;
    dataStream>>pos;
    DragItem *item = new DragItem (this);
    item->setAttribute (Qt::WA_DeleteOnClose);
    item->move(event->pos()-pos);
    item->show();
}
}

void Dialog::mousePressEvent (QMouseEvent *event)
{
if (event->button() != Qt::LeftButton)
{
    event->ignore();
    return;
}
DragItem *item = (DragItem *)(this->childAt(event->pos()));
if (item == NULL)
{
    event->ignore();
    return;
}
else
{
    QMimeData *mimeData = new QMimeData;
    QByteArray exData;
    QDataStream dataStream (&exData, QIODevice::WriteOnly);
    dataStream<<event->pos() - item->pos();
    mimeData->setData("application/x-draganddrop", exData);
    mimeData->setText(tr("Drag and Drop"));
    QDrag *drag = new QDrag (this);
    drag->setMimeData(mimeData);
    drag->setPixmap(*(item->pixmap()));
    drag->setHotSpot(event->pos() - item->pos());
    item->hide();
    if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
      item->close();
    else
      item->show();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值