QListWidget drag&drop item disappear
-
Hi,
I have a QListWidget. Each item has a widget containing the checkboxes Qlabels and button. (I know custom delegate would be better).
I enabled drap and drop with:ui->wbList->setDragDropMode(QAbstractItemView::InternalMove); ui->wbList->setSelectionMode(QAbstractItemView::SingleSelection); ui->wbList->viewport()->setAcceptDrops(true); ui->wbList->setDropIndicatorShown(true); ui->wbList->setDragEnabled(true); ui->wbList->setDefaultDropAction(Qt::MoveAction);
It works but there's a bug : if I drop an item just below itself, then it disappear. Dropping just above works correctly. So it feels like when it's trying to replace itself, in one direction it looses the widget by doing so.
Is there a way to fix that?
Thanks !
Edit: same as this unsolved.
More information here. It is apparantly a bug in newer versions of Qt. -
I found a way to prevent the bug from happening by reimplementing QListWidget and overriding dragMoveEvent :
class QListWidgetDragBugFix : public QListWidget { Q_OBJECT public: QListWidgetDragBugFix(QWidget *parent); ~QListWidgetDragBugFix() override; protected: void dragMoveEvent(QDragMoveEvent *e) override; }; QListWidgetDragBugFix::QListWidgetDragBugFix(QWidget * parent) : QListWidget(parent) { } QListWidgetDragBugFix::~QListWidgetDragBugFix() { } /* Qt has a recent bug (2023, https://bugreports.qt.io/browse/QTBUG-100128) * where the items disappears in certain conditions when drag and dropping. * Here we prevent the situation where this happens. * 1 - If the item is dropped on the item below such that the item doesn't move (ie superior half of the below item) * 2 - The item is the last one and user drop it on the empty space below. * In both those cases the item widget was lost. */ void QListWidgetCustom::dragMoveEvent(QDragMoveEvent *e) { if ((row(itemAt(e->pos())) == currentRow() + 1) || (currentRow() == count() - 1 && row(itemAt(e->pos())) == -1)) { e->ignore(); } else { QListWidget::dragMoveEvent(e); } }
-
Please create bug report about this.
-
@Christian-Ehrlicher
That user has done so in an existing bug referenced from the SO links posted earlier, see https://bugreports.qt.io/browse/QTBUG-100128 -
@JonB thx
-
As written in the bug report I can't reproduce it with Qt 5.15.2 (Linux) or Qt6.6 (Linux + Windows). We need a reproducible example.
-
I work on a very large project so I'm actually not sure how to provide a basic example.
However in this description of the problem : https://stackoverflow.com/questions/74263946/widget-inside-qlistwidgetitem-disappears-after-internal-move
And this one : https://stackoverflow.com/questions/72529707/qlistwidget-items-dissapear-when-drag-dropped
It appears that you just need a 'QListWidget' which is populated by QLabel or QCheckbox via .setItemWidget() and a drag and drop mode InternalMove.
Then you should have this behavior, widget disappearing.
-
I won't write a proper testcase for you. My testcase is working so there is no bug until I see it in a minimal, compilable example.
-
@Christian-Ehrlicher
Oh, that's a complicated case, see https://bugreports.qt.io/browse/QTBUG-100128.
In a nut shell: When aQListWidgetItem
is dragged and dropped, the information about it is rightfully stored in mime data and the item is reconstructed from that data at its new position. That works fine, as long as we're talking about aQListWidgetItem
.In that particular case, an item widget takes it over: It carries the information to be displayed on the screen and the list widget item becomes just a container.
When the drag and drop happens, it's not supported to serialize all information about an arbitrary widget into mime data and reconstruct it upon drop. That case can only be solved on application level. The data necessary to reconstruct an item widget could for instance be stored in a QVariant on list widget item level. The drop event would need to be intercepted and the item widget reconstructed.
It's not a bug.
-
@Axel-Spoerl
Hi Axel. I'm afraid I don't think your explanation is right. Remember the issue is about a particular item, along the lines of the last one and where you drop it to. I don't think "mime data" is relevant here.Have a look again at https://bugreports.qt.io/browse/QTBUG-100128. I think someone else may have posted there subsequent to your post.
-
@JonB
Well, thanks for the reminder, Jon. I will look into that again.
In my tests, the item was prepared to be dragged away, e.g. to another list widget. Loss of widget item is unavoidable in that case. -
@Axel-Spoerl
The OP here wrote in first post:It works but there's a bug : if I drop an item just below itself, then it disappear. Dropping just above works correctly. So it feels like when it's trying to replace itself, in one direction it looses the widget by doing so.
This is an (attempted) drag-drop to move one list item within the
QListWidget
it is already in to a different index within that list widget. For that there should be no serialization/deserialization. It appears there is a specific case --- I think to do with being or being dragged to the last item --- which goes wrong. The "fix" @Paddle has posted into https://bugreports.qt.io/browse/QTBUG-100128 for hisQListWidgetDragBugFix
introduces a special case to ignore whereif ((row(itemAt(e->pos())) == currentRow() + 1) || (currentRow() == count() - 1 && row(itemAt(e->pos())) == -1))
so it's to handle a very specific case.
-
So, it appears that my judgement was wrong. Thanks, @JonB for pointing it out.
I suggest to close this thread and follow the case up in https://bugreports.qt.io/browse/QTBUG-100128.
I'll reopen it. Please check there if the latest reproducer reproduces the problem correctly.
Over and out. -
Fixed in Qt6.6
-
@Christian-Ehrlicher ...and 6.5 and 6.2.
-
@Axel-Spoerl Correct, but imo we should put it into 5.15 too but it's commercial only so no actions from my side possible.
-
@Christian-Ehrlicher I've alrady cherry-picked it there, but integration fails with unrelated errors. Need to investigate...after the weekend.
-