How to perform an action at the end of a QTableView drag-and-drop operation?
-
I have a
QTableView
and would like to perform an action after a drag-and-drop operation.Originally I've added the action at the end of the model's
dropMimeData
method:bool MyTableView::dropMimeData(...) { auto result = super.dropMimeData(...); // perform my action return result }
but that does not work because if I am dragging a row from one point to another, at this point the original row has not yet been deleted, so the table contains two copies of the row at this point, which is an invalid state for my action to be performed. I need to invoke the action only after the row has been completed moved.
I also tried subclassing
QTableView
and overriding itsdropEvent
method:void MyTableView::dropEvent(QDropEvent *event) { super().dropEvent(event); // perform my action }
but it turns out that the chain of events caused by the drag & drop is not completed yet when we leave
super().dropEvent(event)
; the removal of the row from its original location happens afterMyTableView::dropEvent
returns, that is, after my specific action which should happen only after the removal of the row from its original location.The failure of overriding
dropEvent
is particularly puzzling to me because I don't see howsuper().dropEvent()
does not take care of everything before returning.Anyway, is there a way or a place where I can hook this action after the whole drag-and-drop operation is completed, including after the removal of the original row?
-
@Rodrigo-B
Unless you get a better specific answer, which has not happened so far, you can always set off aQTimer
at the end ofdropEvent()
, even possibly with a0
delay, to execute desired code. -
@JonB Thank you! I see, that's a good idea. That should work fine, although it could break if the drag and drop takes longer than my delay. And, if I choose a longer delay to make sure that doesn't happen, then the app is less responsive. But I think it should work pretty well anyway.
I made do with a little hack for now. I set a
doing_drag_and_drop
flag insidedropMimeData
indicating that a drag-and-drop is underway. It seems that the last thing done by the drag-and-drop is to remove the original rows. So, insideremoveRows
, if the flag is true I know a drag-and-drop is ending, so I perform my action and set the flag to false. This works, but it is ugly and could break if Qt changes the order of operations in future versions... -
@Rodrigo-B said in How to perform an action at the end of a QTableView drag-and-drop operation?:
although it could break if the drag and drop takes longer than my delay.
You would start the timer at the end of
dropEvent()
, so the time taken for the drag is not included, only the time for whatever "extra" you do at the end. -
@JonB But that's the thing, at the end of
dropEvent
it seems like the drag-and-drop operators are not yet completed (things like removing rows and so on happen after we exit it).So that's going to take some unspecified time t and we must set the timer to an interval that is guaranteed to be greater than t. If we guess too low, we run the risk of running the action on an inconsistent state, so we must guess high and that may introduce a bit of a delay.
Also, does timer use application-time, or wall time? If wall time, then we would not guarantee correctness because in principle the OS may interrupt the application after
dropEvent
exits but before drag-and-drop is over, and when we resume it the time hits and we run it on an inconsistent state.Anyway, this is all pretty academic, I think in practice your solution would work well.