Reordering TableView with drag and drop
-
Hi,
I implemented my own QAbstractListModel and currently its displayed in a standard QTableview.
I want to allow reordering the elements. Furthermore it must still be possible to drop something from outside the QTableview (no use of setDragDropMode(QAbstractItemView::InternalMove)).
The model is working properly. But currently items are copyed instead of moved.
So I need a way to force the QTableview just to create drags as MoveAction and not as CopyAction.Either I can do this with any features provieded by the QTableview or I must costumize the view.
I already tried the second approach:void CPlaylistWidget::mouseMoveEvent(QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) return; if ((event->pos() - dragStartPosition).manhattanLength() < QApplication::startDragDistance()) return; QDrag *drag = new QDrag(this); drag->setMimeData(this->model()->mimeData(this->selectionModel()->selectedRows())); Qt::DropAction dropAction = drag->exec(Qt::MoveAction); .... }
But now I can't see the moved row during the drag. I know there is the drag->setPixmap method.
But I don't know how to assign a row of the tableview to that.Happy about any suggestions.
-
You can use
QWidget::render()
to create the pixmap that you can assign to yourQDrag
object. You can retrieve the rectangle of your item by usingQAbstractItemView::visualRect()
.Something like this (untested):
void CPlaylistWidget::mouseMoveEvent(QMouseEvent *event) { ... // Retrieve the selected index const QModelIndex& index = currentIndex(); // Render the pixmap QPixmap pixmap; render(&pixmap, visualRect(index)); // Create the drag QDrag* drag = new QDrag(this); drag->setPixmap(pixmap); // Perform the drag switch (drag->exec(Qt::MoveAction)) { } ... }
You should be able to easily adopt that to allow dragging multiple items at once. Obviously you would want to do some sanity checks along the way (eg. checking the rectangle returned by
visualRect()
).I hope that helps.
-
Sounds great, but I get some runtime error:
QPainter::begin: Paint device returned engine == 0, type: 2 QWidget::render: Cannot render with an inactive painter
Edit:
There is some modification on your suggested code neccessary:const QModelIndex& index = currentIndex(); // Render the pixmap QPixmap pixmap(visualRect(index).size()); //pixmap. render(&pixmap, QPoint(), visualRect(index)); // Create the drag QDrag* drag = new QDrag(this); drag->setPixmap(pixmap); ...
But anyhow it renders the cell of one index above the selected one.
Maybe that has something to do with the offset parameter (second one in render).Edit2:
The proper QRect can be calculated with the height of the horizontal header:render(&pixmap, QPoint(0,0), visualRect(index).translated(0, horizontalHeader()->height() ));