Qt - 如何在拖动项目时显示图像/图标/数据?

Posted

技术标签:

【中文标题】Qt - 如何在拖动项目时显示图像/图标/数据?【英文标题】:Qt - How to show image/icon/data while dragging an item? 【发布时间】:2018-05-10 18:40:41 【问题描述】:

我有一个应用程序,我可以将一个项目拖到 QGraphicsScene 并根据项目文本创建一个新对象,但是如何在项目周围移动时更改正在显示的数据?

例如,我想显示一个图标而不是文本:

我有一个包含一些项目的列表:

OptionList::OptionList(QWidget *parent) : QListWidget(parent)

    this->setDragEnabled(true);
    this->setDropIndicatorShown(true);
    this->setSelectionMode(QAbstractItemView::SingleSelection);
    this->setDefaultDropAction(Qt::CopyAction);
    this->setViewMode(QListView::ListMode);

    for(const QString &color : "Blue", "Red", "Green", "Yellow")
    
        OptionItem *item = new OptionItem;
        item->setText(color);
        item->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsDragEnabled);
        addItem(item);
    

我将元素放入场景中以创建一个新对象:

MyScene::MyScene()

    setBackgroundBrush(Qt::lightGray);


void MyScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)

    if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
    event->setAccepted(true);


void MyScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)

    if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
    event->setAccepted(true);


void MyScene::dropEvent(QGraphicsSceneDragDropEvent *event)

    QByteArray encoded = event->mimeData()->data("application/x-qabstractitemmodeldatalist");
    QDataStream stream(&encoded, QIODevice::ReadOnly);

    QStringList colors;

    while (!stream.atEnd())
    
        int row, col;
        QMap<int,  QVariant> roleDataMap;
        stream >> row >> col >> roleDataMap;
        colors << roleDataMap[Qt::DisplayRole].toString();
    

    QPointF posView = event->scenePos() ;

    for(const QString & color: colors)
    
        Block *newBlock = new Block(color);
        newBlock->setPos(posView);
        addItem(newBlock);
    

然后,我创建了派生自 QListWidgetItem 的 OptionItem 类,并重新实现了 mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent

OptionItem::OptionItem()




void OptionItem::mousePressEvent(QGraphicsSceneMouseEvent *event)

    event->setAccepted(true);


void OptionItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)

    QDrag *drag = new QDrag(event->widget());

    QMimeData *mime = new QMimeData;

    QImage image(":/images/MyIcon_icon.png");
    mime->setImageData(image);

    drag->setMimeData(mime);
    drag->setPixmap(QPixmap::fromImage(image));
    drag->setHotSpot(QPoint(15, 30));

    drag->exec();

    event->setAccepted(true);


void OptionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)

    event->setAccepted(true);

我尝试按照 Qt Creator 中的拖放机器人示例进行操作,但这不是一回事

当我开始拖动项目时,图像似乎出现得很快

有没有办法在整个操作中拖动项目时显示图标?

【问题讨论】:

【参考方案1】:

QAbstractItemView 继承的类支持默认拖动,因此它们已经实现了方法,而不是您指出的示例显示了如何为某些没有它的类实现此功能,您的任务很简单,你必须覆盖QListWidget的方法startDrag

optionilist.h

#ifndef OPTIONLIST_H
#define OPTIONLIST_H

#include <QListWidget>


class OptionList: public QListWidget
public:
    OptionList(QWidget* parent=nullptr);

protected:
    void startDrag(Qt::DropActions supportedActions);
;

#endif // OPTIONLIST_H

optionlist.cpp

#include "optionlist.h"

#include <QDrag>

OptionList::OptionList(QWidget *parent): QListWidget(parent)

    setDragEnabled(true);
    setDropIndicatorShown(true);
    setSelectionMode(QAbstractItemView::SingleSelection);
    setDefaultDropAction(Qt::CopyAction);
    setViewMode(QListView::ListMode);

    for(const QString &color : "Blue", "Red", "Green", "Yellow")
        QListWidgetItem *blue = new QListWidgetItem;
        blue->setText(color);
        blue->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsDragEnabled);
        addItem(blue);
    


void OptionList::startDrag(Qt::DropActions supportedActions)
    if(supportedActions & Qt::CopyAction)
        QList<QListWidgetItem *> m_items = selectedItems();
        if(m_items.isEmpty())
            return;
        QMimeData *data = mimeData(m_items);
        QDrag *drag = new QDrag(this);
        QPixmap pixmap(":/images/MyIcon_icon.png");
        drag->setPixmap(pixmap);
        drag->setMimeData(data);
        drag->setHotSpot(pixmap.rect().center());
        drag->exec(Qt::CopyAction);
    
    else
        QListWidget::startDrag(supportedActions);


完整代码可以在以下link找到。

【讨论】:

我在QListWidget中使用了startDrag方法,当我开始拖动item时,应用程序输出打印如下错误:QDrag: No mimedata set before start the drag 我使用了调试器,看起来变量数据到达拖动时没有值->setMimeData(data);也许问题出在 mimeData() 函数上?应用程序成功运行,但当我尝试拖动项目时,应用程序输出中出现消息“QDrag:在开始拖动之前未设置 mimedata”。我也尝试编译您的代码,但由于 nullptr 标识符,我不得不在 .pro 文件中设置 CONFIG += c++11,同样的消息仍然出现在应用程序输出中。 我尝试了你的项目并得到了同样的信息。我已经消除了 OptionItem 实现。我正在使用 Qt 5.4.1 版本。这是我的代码的链接:github.com/Gabriel-22/myqt/tree/master/Project1【参考方案2】:

以上是正确的!

还要注意drag-&gt;setMimeData(data);需要在drag-&gt;setPixmap(pixmap);之后调用。

否则,在拖拽移动的过程中,它会显示原来的mimedata类型,而不是显示图像/图标。

【讨论】:

以上是关于Qt - 如何在拖动项目时显示图像/图标/数据?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 预览图标在代码完成时显示损坏的资产图像

拖动时显示 UIImageView 对象(使用 UILongPressGestureRecognizer)

Android仅在状态栏展开时显示通知

Xcode 9 在 Ctrl+拖动时显示菜单

悬停时显示“关闭”图标

如何在PyQt5中使用QDrag拖动时显示QPushButton?