Solved Drag and drop glitch
-
Hi,
Out of curiosity (and maybe not related to the bug at hand) why aren't you handling the drop in the second model rather that in the view ?
-
@SGaist well, I could handle drop both from view and model, and it seemed less difficult from view, so why not? But thanks a lot, I did handle the drop from the model and there is no glitch anymore.
But the issue now is that when the model drop the loader, the view automatically collapse it, and the item selected is always at the same row, i.e., the item moved is no longer selected.
What I want is:- select the item dropped;
- keep the previous state (expanded or collapsed) for the item dropped.
When I worked on the view, it was easy to know apply selection and state on moved item.
I have to somehow find a signal emitted when the model is done moving and/or view is updated so I can force the item to be selected with the previous expanded/collapsed state. Any idea? -
You could emit a signal from your model that has a QModelIndex and an enum as parameters to signal that e.g.
itemDropped(const QModelIndex& index, StatusFlag flag);
andStatusFlag
being eitherCollapsed
orExpanded
and connect a slot to it that would refresh the view. -
Thanks for your suggestion @SGaist . Unfortunately, I have already tried it but it didn't work: the signal being emitted before the QStandardItemModel::dropMimeData call, the view tries to work on the previous item.
Q_EMIT(expandItemDropped(index(row, column))); return QStandardItemModel::dropMimeData(data, action, realRow, column, parent);
By the way, I can't know from the model if an item is collapsed or expanded, for this is a view matter. Therefore I also emit a signal from the tree view as soon as the item begins to move in order to store that information.
So I'm a bit stuck here. I thought I could delay the signal emission either with a QTimer - which seems to be a VERY BAD idea - or with a QApplication::processEvents - though I've never understood how to use it correctly.
-
What about something like:
bool dropped = QStandardItemModel::dropMimeData(data, action, realRow, column, parent); if (dropped) { Q_EMIT(expandItemDropped(index(realRow, column))); } return dropped;
Or follow the pattern:
WARNING: pseudoCodeemit dropStarted(index); // connect a signal here that store whatever state you need, the parameter might be optional. // do what you need; emit dropEnded(); // act based on the state you stored before return dropped;
-
@SGaist I feel so stupid not having thought to split the method call and the return. Of course this is what I need to do. I guess it's because of the habit to call the parent method at the end, since I obviously split usually when I need to get the value before the return. Thanks a lot!
-
OK, the thing is, when a drop is done, there is a moment while the moved element appears both at the old position AND at the new position in the model. In other words, if the model has n elements, then, there are n+1 elements just after drop is done. Then the old element has to be removed somehow: I can tell since the view is OK and I also checked it through a QAction I triggered to print the model content in console. What I want is to perform actions on view as soon as the model is done dropping mime data, which is not the case obviously right after the QStandardItemModel::dropMimeData() call.
Is there a signal emitted when everything is done? Do I have to emit a custom signal from my reimplemented model? What am I missing?
-
Wouldn't that rather be: blocking update until you've done your processing ?
-
@SGaist maybe, but I'm not sure to understand what you mean by "update". Is it the QTreeView::update method? If so, I don't know how to block it.
Edit: what about reimplementing QAbstractItemModel::moveRows method?
-
I was thinking about the updatesEnabled property.
-
@SGaist Oh, I didn't know that, thanks for the tip!
Actually, I solved my problem. I studied the source code of QAbstractView::dropEvent and found that the method called QAbstractItemModel::dropMimeData. Mine didn't, so I just called the parent dropEvent. Instead of handling drag and drop from the model, I reused my old code, handling it from the view and simply call the parent dropEvent when creating the loader from a category. Doing so, the model dropMimeData was actually called and there was no more glitch.
Thanks for all your inputs, they were really helpful!