Qt drag & drop

Qt drag & drop

Example: draggable Icons

用户将一个widget中的东西,这个例子中是QLable控件拖动至另一个widget,这个例子甚至支持程序2个实例之间的拖拽操作。Widget之间和程序实例之间拖拽操作结果是复制一个lable并将其放到鼠标release的位置上。

传输的信息不仅包含QLable本身包含的图片信息,还有鼠标点击位置信息,这样用户就能精确放置Icon位置了。不过这需要MIME类型格式。

 

MIME格式多用途互联网邮件扩展MIMEMultipurpose Internet Mail Extensions)是一个互联网标准,它扩展了电子邮件标准,使其能够支持非ASCII字符、二进制格式附件等多种格式的邮件消息。MIME是通过标准化电子邮件报文的头部的附加域(fields)而实现的;这些头部的附加域,描述新的报文类型的内容和组织形式。

 

用于放置icon的widget:

class DragWidget : public QFrame
 {
 public:
    DragWidget(QWidget *parent=0);
 
 protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dragMoveEvent(QDragMoveEvent *event);
    void dropEvent(QDropEvent *event);
     voidmousePressEvent(QMouseEvent *event);
 };

构造函数:

DragWidget::DragWidget(QWidget *parent)
    : QFrame(parent)
 {
    setMinimumSize(200, 200);
    setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
    setAcceptDrops(true);
 
    QLabel *boatIcon = new QLabel(this);
    boatIcon->setPixmap(QPixmap(":/images/boat.png"));
    boatIcon->move(20, 20);
    boatIcon->show();
    boatIcon->setAttribute(Qt::WA_DeleteOnClose);
 
    QLabel *carIcon = new QLabel(this);
    carIcon->setPixmap(QPixmap(":/images/car.png"));
    carIcon->move(120, 20);
    carIcon->show();
    carIcon->setAttribute(Qt::WA_DeleteOnClose);
 
    QLabel *houseIcon = new QLabel(this);
    houseIcon->setPixmap(QPixmap(":/images/house.png"));
    houseIcon->move(20, 120);
    houseIcon->show();
    houseIcon->setAttribute(Qt::WA_DeleteOnClose);
 }

houseIcon->setAttribute(Qt::WA_DeleteOnClose);
//这句话表示Qt将在QLable控件接受closeEvent的时候删除之。
//[疑问]那不写这句话会怎么样呢?

从起始位置实现拖操作,必须有一个鼠标点击事件函数:

voidDragWidget::mousePressEvent(QMouseEvent *event)
 {
    QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
    if (!child)
        return;
 
     QPixmap pixmap = *child->pixmap();
 
    QByteArray itemData;
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    dataStream << pixmap << QPoint(event->pos() -child->pos());

这里用了QByteArray打包了pixmap和鼠标移动造成的偏移向量信息。用dataStream写入到QByteArray非常方便。

 

使用QMimeData保存这些信息,据说是为了interoperability(两台不同电脑共同工作交通的能力):

    QMimeData *mimeData = new QMimeData;
    mimeData->setData("application/x-dnditemdata", itemData);

QMineData有个setData(),可以直接将一个QByteArray参数传入。第一个参数一个字符串用于指定这个MIME的format,方便其他widget或者程序识别拖拽信息。

 

拖拽操作本身由一个QDrag完成:

    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);//将数据传给drag
    drag->setPixmap(pixmap);//拖拽过程中显示的图片
    drag->setHotSpot(event->pos() - child->pos());
    //Hot Spot是一个精确定位鼠标位置的东东,event->pos()指示鼠标点击的位置。
    //Setsthe position of the hot spot relative to the top-left corner of the pixmap usedto the point specified by hotspot.

voidDragWidget::dragEnterEvent(QDragEnterEvent *event)
 {
    if(event->mimeData()->hasFormat("application/x-dnditemdata")) {
        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
 }

其中的acceptProposedAction()。一个drop event包含了一个proposed action,这个action到底是什么可以从proposedAction()获得,无论这个widget是否接受这个event。如果widget能够处理这个event,那么应该调用一下acceptProposedAction()函数。因为proposed action是一个Qt::DropAction枚举的混合,选用这些枚举中的其中一个作为默认的action或者让用于选择(用户可以在放下物件的时候选择操作,复制,移动什么的)非常有用。

Constant Value Description
Qt::CopyAction 0x1 Copy the data to the target.
Qt::MoveAction 0x2 Move the data from the source to the target.
Qt::LinkAction 0x4 Create a link from the source to the target.
Qt::ActionMask 0xff  
Qt::IgnoreAction 0x0 Ignore the action (do nothing with the data).
Qt::TargetMoveAction 0x8002 On Windows, this value is used when the ownership of the D&D data should be taken over by the target application, i.e., the source application should not delete the data. 
On X11 this value is used to do a move. 
TargetMoveAction is not used on the Mac.

voidDragWidget::dragMoveEvent(QDragMoveEvent *event)
 {
    if(event->mimeData()->hasFormat("application/x-dnditemdata")) {
        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
         }
    } else {
        event->ignore();
    }
 }

 

void DragWidget::dropEvent(QDropEvent *event)//一个对信息的解锁过程
{
    if(event->mimeData()->hasFormat("application/x-dnditemdata")) {
       QByteArray itemData = event->mimeData()->data("application/x-dnditemdata");
       QDataStream dataStream(&itemData, QIODevice::ReadOnly);
       
       QPixmap pixmap;
       QPoint offset;
       dataStream >> pixmap >> offset;
 
       QLabel *newIcon = new QLabel(this);
       newIcon->setPixmap(pixmap);
       newIcon->move(event->pos() - offset);
       newIcon->show();
       newIcon->setAttribute(Qt::WA_DeleteOnClose);
 
       if (event->source() == this) {
           event->setDropAction(Qt::MoveAction);
           event->accept();
       } else {
           event->acceptProposedAction();
       }
    }else {
       event->ignore();
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值