PDA

View Full Version : When should QTreeWidget::dropMimeData be called?



rainbowgoblin
27th March 2014, 23:14
I'm trying to create a dialog with a (derived) QListWidget on the left and a (derived) QTreeWidget on the right. Users should be able to drag items from the list widget and drop them into the tree widget. Child items in the tree widget can also be moved to a different parent (top level item).

I initially reimplemented startDrag() in the list widget, and dragEnterEvent(), dragMoveEvent(), and dropEvent() in the tree widget. I encoded some mime data in startDrag(), and decoded it in dropEvent(), and removed the dragged-and-dropped items from the list widget if all went well. This all worked more or less, but I couldn't figure out how to make the "drop indicator" appear in the tree widget when I was dragging an item in. While searching for a solution, I discovered I was doing things all wrong, and tried a different approach.

I've reimplemented mimeData() in the list widget, and reimplemented dropMimeData() in the tree widget. This doesn't work: dropMimeData() is never called. I've got the following options set up on the tree widget:


theTreeWidget->setDragEnabled(true);
theTreeWidget->setAcceptDrops(true);
theTreeWidget->setDragDropMode(QAbstractItemView::InternalMove);


So first question: Why isn't dropMimeData() called? I tried changing the drag drop mode to DragDrop, because I though this might help. When I do, dropMimeData() is called, but ONLY when I drag and drop items from within the tree, not from the list widget. Also, tree widget items are copied, rather than moved (I guess this is expected behaviour). So I tried to reimplement the supportedDropActions() function so that only MoveAction is returned. Now dropMimeData is no longer called, and I get weird behaviour:

1. When I have two top-level items, and one child item under the first, I try to move the child to the other top-level item. The child becomes a top-level item and its parent is deleted. Some screen shots, before: 10189 and after: 10190

2. When I have two top-level items, and two children under the first, I try to move the second child to the other top-level item. The child moves appropriately, but its "sibling" is deleted. Before: 10192, and after:10191

Second question: Is this normal behaviour? I've looked through my code, and there's only one function where I delete or take items from the tree widget, and it isn't called during dragging and dropping (I added a qDebug() call to make sure).

rainbowgoblin
28th March 2014, 04:33
I've figured out most of my problem. I'm still not sure about the weirdness when QTreeWidget::supportedDropActions() is reimplemented, but I've got the rest of it. I'm posting my solution because I've seen other related questions and I think that my solution might lead to an answer for a few people.


In addition to reimplementing QListWidget::mimeData() and QTreeWidget::dropMimeData(), I needed to reimplement mimeTypes() in both classes. This was well-documented in the model-view-programming documentation, but apparently I can't read.
Using QTreeWidget::setDragDropMode() to set the drag/drop mode to QAbstractItemView::DragDrop is important for receiving drag/drop events from the list widget as well as allowing internal drag and drop (within the tree widget).
I also had to reimplement QTreeWidget::mimeData() so that internal drag and drop events in the tree widget would be handled properly. This probably wasn't entirely necessary, but I think it simplified forcing internal drag and drop events to be move actions later.
At this stage, drag and drop worked, but only to copy items. Reimplementing QTreeWidget::supportedDropActions() to allow only Qt::MoveAction did NOT work. As stated above, it just resulted in items being deleted that shouldn't have been... I'm pretty sure this is a Qt bug (I'm using Qt 4.8).
Getting my whole setup to move things (as opposed to copying) required reimplementing QListWidget::startDrag() QTreeWidget::startDrag() in order to create QDrag instances that executed MoveActions.



Without further ado, here's a working example!

10196
10197
10194
10195