Why are widgets deleted?
When the drag and drop is performed, the data of the selected items is coded (roles and associated values) and saved in a QMimeData
. When the drop is accepted, the source items are deleted and new items are created with the information stored in the QMimeData
, inside the saved information there is no widgets information since this does not have relation with the model. And since the items are deleted, their widgets are also deleted.
To check it we can use the following example
#include <QApplication>
#include <QLabel>
#include <QTreeWidget>
#include <QDebug>
static void on_destroyed(){
qDebug()<<"destroyed";
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTreeWidget w;
w.setSelectionMode(QAbstractItemView::SingleSelection);
w.setDragEnabled(true);
w.viewport()->setAcceptDrops(true);
w.setDropIndicatorShown(true);
w.setDragDropMode(QAbstractItemView::InternalMove);
for(int i=0; i< 5; i++){
QTreeWidgetItem *it = new QTreeWidgetItem(&w);
QLabel *lbl = new QLabel(QString::number(i));
QObject::connect(lbl, &QObject::destroyed, on_destroyed);
w.setItemWidget(it, 0, lbl);
}
w.show();
return a.exec();
}
It shows that the widgets will emit the signal they destroy when you drag and drop the items.
Possible workaround:
One possible solution is to remove the widgets before accepting the drop and set them in the new items which I have not implemented.
I have explored another solution, it is to change the QTreeWidget
for a QTreeView
+ QStandardItemModel
. In the case of the QCheckBox
, the checkboxes with the Qt::ItemIsUserCheckable
flag are enabled, in the case of the QLineEdit
a delegate will be used and to always be shown, the openPersistentEditor()
method must be used.
#include <QApplication>
#include <QStandardItemModel>
#include <QTreeView>
#include <QHeaderView>
#include <QDropEvent>
#include <QStyledItemDelegate>
#include <QLineEdit>
class ToolsSelectorDelegate: public QStyledItemDelegate{
public:
using QStyledItemDelegate::QStyledItemDelegate;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const{
QLineEdit *le = new QLineEdit(parent);
return le;
}
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const{
QRect r(option.rect);
r.adjust(2, 2, -2, -2);
editor->setGeometry(r);
}
};
class ToolsSelectorWidget: public QTreeView{
QStandardItemModel model;
public:
ToolsSelectorWidget(QWidget *parent=nullptr): QTreeView(parent){
setItemDelegate(new ToolsSelectorDelegate(this));
setModel(&model);
header()->hide();
setSelectionMode(QAbstractItemView::SingleSelection);
setDragEnabled(true);
viewport()->setAcceptDrops(true);
setDropIndicatorShown(true);
setDragDropMode(QAbstractItemView::InternalMove);
for(int i=0; i<4; ++i) {
QList<QStandardItem *> items;
for(const QString & text: {"Preview", "Name", "Visible", "Locked"}){
QStandardItem *it = new QStandardItem(QString("Part%1 %2").arg(i).arg(text));
it->setFlags(it->flags() & ~Qt::ItemIsDropEnabled & ~Qt::ItemIsEditable);
items.append(it);
if(text == "Visible" || text == "Locked"){
it->setFlags(it->flags() | Qt::ItemIsUserCheckable);
it->setCheckState(Qt::Unchecked);
}
else if (text == "Name") {
it->setFlags(it->flags() | Qt::ItemIsEditable);
}
}
for(const QString & children: {"The", "quick", "Brown", "fox", "jump...", "over", "the", "lazy", "dog"})
items.first()->appendRow(new QStandardItem(children));
model.invisibleRootItem()->appendRow(items);
for( int i = 0; i < model.rowCount(); ++i )
openPersistentEditor(model.index(i, 1));
}
}
protected:
void dropEvent(QDropEvent *event) {
QModelIndex droppedIndex = indexAt(event->pos());
if( !droppedIndex.isValid() || droppedIndex.parent().isValid())
return;
QTreeView::dropEvent(event);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ToolsSelectorWidget w;
w.show();
return a.exec();
}
part->setFlags(part->flags() & Qt::ItemFlag((~Qt::ItemIsDropEnabled)));
– Pasteurize