QListWidget 拖放与通过 setItemWidget 设置的自定义小部件

Posted

技术标签:

【中文标题】QListWidget 拖放与通过 setItemWidget 设置的自定义小部件【英文标题】:QListWidget drag and drop with a custom widget set via setItemWidget 【发布时间】:2018-04-05 19:45:35 【问题描述】:

我正在使用 QListWidget 来显示自定义小部件,方法是使用 setItemWidget 设置它们。像这样的:

QListWidget* listWidget = new QListWidget;
listWidget->setAcceptDrops(true);
listWidget->setDragDropMode(QAbstractItemView::InternalMove);
listWidget->setDragEnabled(true);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);

for ( int i = 0 ; i < 50 ; ++i )

    ItemWidget* item = new ItemWidget;
    QListWidgetItem* listItem = new QListWidgetItem;
    listItem->setSizeHint(item->sizeHint());
    listWidget->addItem(listItem);
    listWidget->setItemWidget(listItem, item);

ItemWidget 派生自 QWidget,只是在布局中显示一些自定义数据,如下所示:

ItemWidget::ItemWidget()

    QVBoxLayout* layout = new QVBoxLayout;
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);

    QHBoxLayout* contentLayout = new QHBoxLayout;
    contentLayout->setSizeConstraint(QLayout::SetFixedSize);
    contentLayout->setSpacing(0);

    contentLayout->addSpacing(5);
    contentLayout->setContentsMargins(10, 20, 10, 20);

    QLabel* iconLbl = new QLabel;
    iconLbl->setPixmap(QPixmap(":/icon.png"));
    iconLbl->setMaximumWidth(20);
    contentLayout->addWidget(iconLbl, 0, Qt::AlignTop);

    contentLayout->addSpacing(14);

    QVBoxLayout* infoLayout = new QVBoxLayout;
    infoLayout->setContentsMargins(0, 0, 0, 0);
    infoLayout->setSpacing(0);

    QLabel* firstLbl = new QLabel("First line of text");
    infoLayout->addWidget(firstLbl);

    infoLayout->addSpacing(4);

    QLabel* secondLbl = new QLabel("Second line of text");
    infoLayout->addWidget(secondLbl);

    contentLayout->addLayout(infoLayout);

    layout->addLayout(contentLayout);

    setLayout(layout);

我想实现拖放以重新排列列表中的项目。但是,当使用 setItemWidget 时,当鼠标拖动项目时,只会拖动背景矩形(QListWidgetItem ?),而不会显示任何属于 ItemWidget 的自定义内容。我希望被拖动的项目也包含 ItemWidget 内容,以便用户看到被拖放的内容。

有没有人有实现这个的可行方法?

我已经尝试使用派生自 QListWidgetItem 和 QWidget 的自定义类,并直接在该类中设置自定义布局,因此可能不需要 ItemWidget 或使用 setItemWidget,但它并没有像我希望的那样工作.

【问题讨论】:

我已经用更多示例代码更新了这个问题。谢谢! 嗯,不。这正是我的意思。正在拖动蓝色矩形,但没有任何文本被拖动。我想看到被拖动的整个小部件,而不仅仅是“轮廓”。 【参考方案1】:

要自定义与QListWidgetQDrag 关联的QPixmap,我们必须重写startDrag() 方法。

主要任务是获取一个QPixmap为它选择的元素创建一个QPixmap的可见图像的大小是透明的viewport()然后我们用QPixmap绘制它们每个为其选择的项目我们使用QPainter

获取每一项的QPixmap,使用grab()方法,表示通过visualRect()获取的矩形。

#ifndef LISTWIDGET_H
#define LISTWIDGET_H

#include <QListWidget>
#include <QDrag>
#include <QMimeData>
#include <QPainter>

class ListWidget : public QListWidget

protected:
    void startDrag(Qt::DropActions supportedActions)
        QDrag *drag = new QDrag(this);
        drag->setMimeData(model()->mimeData(selectedIndexes()));
        QPixmap pixmap(viewport()->visibleRegion().boundingRect().size());
        pixmap.fill(Qt::transparent);
        QPainter painter(&pixmap);
        for(QModelIndex index: selectedIndexes())
            painter.drawPixmap(visualRect(index), viewport()->grab(visualRect(index)));
        
        drag->setPixmap(pixmap);
        drag->setHotSpot(viewport()->mapFromGlobal(QCursor::pos()));
        drag->exec(supportedActions, Qt::MoveAction);
    
;

#endif // LISTWIDGET_H

完整的例子可以在下面的link找到

【讨论】:

以上是关于QListWidget 拖放与通过 setItemWidget 设置的自定义小部件的主要内容,如果未能解决你的问题,请参考以下文章

nstableview 拖放与自定义单元格视图

IOS拖放与缩放

如何使用 jQuery 拖放与段落元素

拖放与物理行为

如何让 jQueryUI 拖放与触摸设备一起使用

AngularJS - 将拖放与流程图相结合