3
votes

I'm using a QListWidget to display custom widgets by setting them with setItemWidget. Something like this:

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 is derived from QWidget, and just displays some custom data in a layout, like this:

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);
}

I'd like to implement drag & drop to be able to rearrange the items in the list. However, when using setItemWidget, when the mouse is dragging the item, only the background rectangle (the QListWidgetItem ?) is dragged around, with none of the custom content that's part of the ItemWidget showing. I'd like the item being dragged to include the ItemWidget content as well, so the user sees what's being dragged and dropped.

Does anyone have a working approach of implementing this?

I've already tried using a custom class derived from both QListWidgetItem and QWidget, and setting a custom layout directly in that class, thereby perhaps not needing an ItemWidget or using setItemWidget, but it didn't work out as I had hoped.

1
I have updated the question with more example code. Thanks!Anon
Well, no. That's exactly what I mean. The blue rectangle is being dragged, but none of the text is being dragged with it. I'd like to see the entire widget, being dragged, not just the "outline".Anon

1 Answers

3
votes

To customize the QPixmap associated with the QDrag of QListWidget we must override the startDrag() method.

The main task is to get a QPixmap of the elements selected for it is created a QPixmap the size of the visible image of the viewport() that is transparent and then we paint them with QPixmap of each item selected for it we use QPainter.

To obtain the QPixmap of each item, use the grab() method, indicating the rectangle obtained through 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

The complete example can be found in the following link