Search code examples
c++qtqt5qcomboboxqlistwidget

Drag and drop listwidget items with a combobox inside


I have two listwidgets in icon mode list1 is a list of 100 widget items (each Widget item is an icon packed with a combobox with 3-4 items inside) . Those combobox items are data of the icon this will never change ,they are packed with the Widget item ,listwidget2 is empty and I just want to be able to drag the widget item(icon and combobox with items) from 1 and make a favorite list with some widgets of list1, nothing will change to combobox items or the widget items of list1 they will have always the same data, the problem is that each time I drag the widget only the icon is copied to the other listwidget.

 QDir dir ("icons");
 QFileInfoList list = dir.entryInfoList(QDir::AllEntries | 
 QDir::Dirs|QDir::NoDotAndDotDot);

 for(int i=0 ; i < list.length() ; i++){
 dir_names.push_back(list.at(i).baseName());
 /*Setting the icon*/
 QIcon icon;
 icon.addFile(list.at(i).absoluteFilePath(), QSize(), QIcon::Normal, 
 QIcon::Off);
 QListWidgetItem *iconItem = new QListWidgetItem(ui->listWidget);
 iconItem->setIcon(icon);

 QComboBox *box = new QComboBox;
 QListWidgetItem *textItem = ui->listWidget->item(i);

 ui->listWidget->setItemWidget( textItem,box);
 box->setFixedHeight(18);
 box->addItem(list.at(i).baseName());
 }

Solution

  • If you want the combobox to be moved you must overwrite the dropEvent method so you must create a class that inherits from QListWidget, get the widget and copy the necessary data. If you want to use it in Qt Designer you must promote it.

    listwidget.h

    #ifndef LISTWIDGET_H
    #define LISTWIDGET_H
    
    #include <QListWidget>
    
    class ListWidget : public QListWidget
    {
        Q_OBJECT
    public:
        ListWidget(QWidget * parent = 0);
        void dropEvent(QDropEvent * event);
    
    protected:
        void mouseMoveEvent(QMouseEvent * event);
    };
    
    #endif // LISTWIDGET_H
    

    listwidget.cpp

    #include "listwidget.h"
    
    #include <QDropEvent>
    #include <QComboBox>
    
    ListWidget::ListWidget(QWidget *parent):QListWidget(parent)
    {
        setDragEnabled(true);
        setAcceptDrops(true);
        setDropIndicatorShown(true);
        setDefaultDropAction(Qt::MoveAction);
    }
    
    void ListWidget::dropEvent(QDropEvent *event)
    {
        if(event->dropAction() == Qt::MoveAction && event->source()){
            ListWidget *listWidget = qobject_cast<ListWidget *>(event->source());
            if(!listWidget)
                return;
    
            QList<QPersistentModelIndex> pIndexes;
            for(QModelIndex index: listWidget->selectedIndexes()){
                pIndexes << QPersistentModelIndex(index);
            }
    
            std::sort(pIndexes.begin(), pIndexes.end());
    
            QListWidgetItem *item = itemAt(event->pos());
            int rowStart = item? row(item) : count();
    
            for(QPersistentModelIndex pindex: pIndexes){
                int r = QModelIndex(pindex).row();
                QComboBox *input = qobject_cast<QComboBox *>(listWidget->itemWidget(listWidget->item(r)));
    
                QComboBox *output;
                if(input){
                    // move data to QComboBox
                    output = new QComboBox;
                    for(int i=0; i<input->count(); i++){
                        output->addItem(input->itemText(i));
                        output->setCurrentText(input->currentText());
                    }
                }
    
                QListWidgetItem *it = listWidget->takeItem(r);
                insertItem(rowStart, it);
                if(input)
                    setItemWidget(it, output);
            }
            setState(QAbstractItemView::NoState);
        }
    }
    
    void ListWidget::mouseMoveEvent(QMouseEvent *event)
    {
        setState(QAbstractItemView::DraggingState);
        QListWidget::mouseMoveEvent(event);
    }
    

    In the following link there is an example.