I'm learning how to setup drag and drop in the view-model framework description at Qt site. When applied to convenience views (QListWidget
, QTableWidget
, QTreeWidget
), the documentation uses either (in original C++ version):
listWidget->setDragEnabled(true);
listWidget->viewport()->setAcceptDrops(true);
or:
listWidget->setDragDropMode(QAbstractItemView::InternalMove);
I'm unable to figure out whether setDragDropMode
is a shortcut to set individual properties of the widget and which ones in addition of the two above, or it actually does more. I see using QAbstractItemView::InternalMove
and QAbstractItemView::DragDrop
both set DragEnabled
and setAcceptDrops
to true
, but lead to a different behavior for the item (move vs. copy), so I know there is more behind the mode method. I would like to clarify this point in order to know when to use the mode method.
My questions:
I use Qt for Python if that matters.
As an example, if I create a list widget with each approach, it seems the result is perfectly equivalent (in this specific case):
from qtpy.QtWidgets import (QApplication, QWidget, QListWidget, QHBoxLayout)
class Window(QWidget):
texts = ['Sycamore', 'Chestnut', 'Walnut', 'Mahogany']
def __init__(self):
super().__init__()
lw_1 = QListWidget()
lw_1.addItems(self.texts)
self.print_props('When created', lw_1)
lw_2 = QListWidget()
lw_2.addItems(self.texts)
# Comparing
lw_1.setDragEnabled(True)
lw_1.viewport().setAcceptDrops(True)
lw_1.setDropIndicatorShown(True)
self.print_props('Using properties', lw_1)
# With
mode = lw_2.DragDrop
lw_2.setDragDropMode(mode)
self.print_props(f'Using mode ({mode})', lw_2)
layout = QHBoxLayout(self)
layout.addWidget(lw_1)
layout.addWidget(lw_2)
def print_props(self, text, widget):
print()
print(text)
print('drag:', widget.dragEnabled())
print('drop:', widget.viewport().acceptDrops())
print('mode:', widget.dragDropMode())
def main():
app = QApplication([])
window = Window()
window.show()
app.exec()
main()
We can look at the source of the getter and setter of dragDropMode
property:
void QAbstractItemView::setDragDropMode(DragDropMode behavior)
{
Q_D(QAbstractItemView);
d->dragDropMode = behavior;
setDragEnabled(behavior == DragOnly || behavior == DragDrop || behavior == InternalMove);
setAcceptDrops(behavior == DropOnly || behavior == DragDrop || behavior == InternalMove);
}
QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const
{
Q_D(const QAbstractItemView);
DragDropMode setBehavior = d->dragDropMode;
if (!dragEnabled() && !acceptDrops())
return NoDragDrop;
if (dragEnabled() && !acceptDrops())
return DragOnly;
if (!dragEnabled() && acceptDrops())
return DropOnly;
if (dragEnabled() && acceptDrops()) {
if (setBehavior == InternalMove)
return setBehavior;
else
return DragDrop;
}
return NoDragDrop;
}
As you can see, the setter indeed itself uses setDragEnabled
and setAcceptDrops
to set corresponding properties, which corresponds to behaviour you noticed. The only additional thing it does is setting underlying d->dragDropMode
(d
appears via Q_D
macro and is used to implement private data, see this question), but the getter doesn't even consider its value except when dragEnabled() && acceptDrops()
, for which case, as you observed, the saved member differentiates between move and copy behaviour. By default it is set to QAbstractItemView::NoDragDrop
(see here), so the getter returns DragDrop
(whenever it is called by you or Qt itself) if you didn't set the property yourself and used only setDragEnabled
and setAcceptDrops
(setting them to true
). Also note that the getter and setter aren't virtual
(see here).
So, if you don't need InternalMove
behaviour, you can ignore dragDropMode
propery and just use setDragEnabled
and setAcceptDrops
, behaviour will be identical.