0
votes

Here's what I'm trying to do: I have certain data that is displayed through a custom widget. There is a lot of such data. At runtime, the user will be presented with a list of all data and they will choose which ones they want to monitor, which will dynamically create the custom widget in a grid. I want to let the users reorganize the widgets in the grid as they please, preferably though drag and dropping.

The closest thing I could find to achieve this is using a QTableWidget with the following properties: setDragEnabled(True), setDragDropOverwriteMode(False), setDragDropMode(QtGui.QAbstractItemView.InternalMove). With these properties, it's possible to drag cells and move them to other cells.

However, this seems to only work with the QTableWidgetItem attached to each cell, not the widgets set though setCellWidget().

Here is a small project illustrating what I'm trying to do: https://gist.github.com/anonymous/02bbcc201316fa8f43e9

You can see that the widgets created (by clicking on the button) are not drag'n'droppable, however if you edit a cell (which sets the QTableWidgetItem), those are drag'n'droppable. It seems the cellWidget part and the item part of a cell are completely independent, and the drag and drop logic only applies to the items, not the cell widgets.

I'm afraid I already know the answer, but... is there any way to do what I want, short of replacing the QTableWidget by a QTableView, using a model, and re-implementing all the drag and drop logic myself?

Or maybe my approach is completely wrong. Maybe there's some other widget or Qt facility that I can use? I'm open to any and all suggestions.

Thanks in advance!

1
As a workaround, try to detect drops and move cell widgets manually. I'm not sure how to do that, though. I think Qt's Model/View doesn't fit well in your usecase (unless you need some complex features like cell selection handling). Just implement drag and drop in a QGridLayout manually.Pavel Strakhov

1 Answers

1
votes

I'm not sure how okay it is for someone to answer their own question, but I solved my problem and I thought I'd offer my solution. Maybe it'll help someone in the future.

Here is what I did:

First, I wrote a GridWidget deriving from QTableWidget, with a custom dropEvent() method to handle moving widgets around.

Due to the way QAbstractListView manages the list of widgets attached to indexes, it's not possible to move existing widgets around, because the widget in the original cell will be destroyed. So I wrote a ContainerWidget that is simply a layout for another widget. The ContainerWidget class has a cloneAndPassContainedWidget() method that does what you'd expect: it returns a new ContainerWidget and gives it ownership of the contained widget. Obviously, after calling the method, the original ContainerWidget becomes useless, but the method is called (and exists) precisely because the widget is set to be destroyed, so that's not a problem.

Here is a simple project showing my solution in practice: https://gist.github.com/anonymous/a3b2d7e61c6b3e11742c

I'm fairly sure the proper way would have been to write a model, views and delegates, but in my case that would have required too much work, so this solution is an acceptable workaround.