Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTableView drag and drop both reorder and to other QTableViews



  • I have several QTableViews. The goal is to be able to drag-and-drop items between them as well as use drag-and-drop to reorder items internally in the views.

    My first approach was to use a QTableWidget and set the dragDropMode to InternalMove. With some tweaking by overriding QTableWidget::dropEvent the internal reordering worked but it wasn't possible to drag from the widget to another widget.

    I thought the solution was to use the model-view approach since what would enable me to provide data when a drag started by reimplementing QAbstractItemModel::mimeData(). By testing I found out that when dragDropMode is set to InternalMove the model methods for drag-and-drop as outlined in https://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views are not called. Hence dragDropMode must be set to DragDrop to enable drag and drop to other widgets. However when I do that the visual feedback when the user drags the item over the destination QTableView isn't good. With the QTableWidget solution a line indicator showing where the dropped item would be inserted was painted. But with the QTableView the visual feedback is just that the destination cell is selected. This is very confusing for the user and not acceptable. If the entire destination row was painted it would be a little bit better. selectionBehaviour is set to selectRows hence it doesn't seem to affect the painting of the destination. dragDropOverwriteMode doesn't seem to affect the behavior.

    Anyone who has a good solution or even accomplished the goal, to be able to drag-and-drop items between qtableviews as well as use drag-and-drop to reorder items internally in the views.



  • @olowo726 said in QTableView drag and drop both reorder and to other QTableViews:

    With the QTableWidget solution a line indicator showing where the dropped item would be inserted was painted. But with the QTableView the visual feedback is just that the destination cell is selected.

    I don't know a good answer to your problem, perhaps someone else will. But you seem to be saying here that plain QTableView lacks what you want while QTableWidget has something acceptable? Are you aware that QTableWidget is just a layer on top of QTableView --- and a lot of that to do with the internal model data --- would it be worth taking a look at source code (e.g. https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtablewidget.cpp.html) to see if you easily spot what they are doing?



  • @JonB Yes, QTableWidget have a graphical presentation that is acceptable if I set the dragDropMode to InternalMove. But if I do that it won't work to drag and drop between widgets...


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    There's no ready made solution for you. From the top of my head, I remember something about changing the drag and drop mode dynamically. Likely using the enter/leave events.



  • @SGaist @JonB With inspiration from QTableWidget sources my approach for internal reordering is now to override dropEvent and in there use moveRows.

    if (event->source() == this)
          {
             // It's an internal move, a solution based on overridden QAbstractItemModel::moveRows
    

    That works for internal reordering.

    It seems like QDrag::exec is supposed to return an action performed but I find no information on how the information about a successful drop shall get back to the source widget and also the call to QDrag::exec is buried deep within a mouse event handler for QAbstractItemView.

    My solution is to also implement copy-or-move in an overridden dropEvent. First let the base class process the drop event. If accepted then check keyboard modifers. If not ctrl modifier, i.e. if move, then use the event source to find the source widget and call remove on the source widget.