这个问题类似于这个主题 Preserve QStandardItem subclasses in drag and drop 中的问题,但是我找不到一个好的解决方案。这个主题在一定程度上有所帮助,但在更复杂的任务中失败了。
当我在QTreeView中创建一个项目时,我将该项目放入我的数组中,但是当我使用拖放操作时,该项目被删除,并且我不再能够访问它。我知道这是因为拖放复制了项目,而不是移动它,所以我应该使用setData。我不能setData成为一个对象,因为即使这样,对象也被复制了,我失去了对它的引用。
下面是一个例子
itemsArray = self.addNewRow def addNewRow(self) '''some code with more items''' itemHolder = QStandardItem("ProgressBarItem") widget = QProgressBar() itemHolder.setData(widget) inx = self.model.rowCount() self.model.setItem(inx, 0, itemIcon) self.model.setItem(inx, 1, itemName) self.model.setItem(inx, 2, itemHolder) ix = self.model.index(inx,2,QModelIndex()) self.treeView.setIndexWidget(ix, widget) return [itemHolder, itemA, itemB, itemC] #Simplified functionality data = [xxx,xxx,xxx] for items in itemsArray: items[0].data().setPercentage(data[0]) items[1].data().setText(data[1]) items[2].data().setChecked(data[2])
如果我不移动小部件,上面的代码就可以工作。在我拖/放的那一秒,我丢失了引用,我丢失了所有项目的更新,并且我崩溃了。
RuntimeError: wrapped C/C++ object of type QProgressBar has been deleted
我能想到的解决这个问题的方法是递归地循环遍历整个treeview,遍历每一行/子对象和名称匹配更新项。问题是,我将每0.5秒刷新一次树视图,并拥有每个包含5-15个项目的500+行。意思是..。我不认为这将是非常快/有效的。如果我想每0.5秒循环5000个项目...
有人能建议我如何解决这个问题吗?也许我可以编辑dropEvent,这样它就不会复制/粘贴项目,而是移动项目...这样我就不会丢失数组中的对象。
发布于 2016-11-07 04:27:34
Qt只能序列化可以存储在 QVariant 中的对象,所以这不适用于 QWidget 也就不足为奇了。但是,即使它可以序列化小部件,我仍然认为它不会工作,因为索引小部件属于视图,而不是模型。
QVariant
QWidget
无论如何,我认为您必须单独保留对小部件的引用,并且只在模型项中存储一个简单的键。然后,一旦项目被删除,您就可以检索小部件并在视图中重置它们。
下面是一个有效的演示脚本:
from PyQt4 import QtCore, QtGui class TreeView(QtGui.QTreeView): def __init__(self, *args, **kwargs): super(TreeView, self).__init__(*args, **kwargs) self.setDragDropMode(QtGui.QAbstractItemView.InternalMove) self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.setAllColumnsShowFocus(True) self.setModel(QtGui.QStandardItemModel(self)) self._widgets = {} self._dropping = False self._droprange = range(0) def dropEvent(self, event): self._dropping = True super(TreeView, self).dropEvent(event) for row in self._droprange: item = self.model().item(row, 2) self.setIndexWidget(item.index(), self._widgets[item.data()]) self._droprange = range(0) self._dropping = False def rowsInserted(self, parent, start, end): super(TreeView, self).rowsInserted(parent, start, end) if self._dropping: self._droprange = range(start, end + 1) def addNewRow(self, name): model = self.model() itemIcon = QtGui.QStandardItem() pixmap = QtGui.QPixmap(16, 16) pixmap.fill(QtGui.QColor(name)) itemIcon.setIcon(QtGui.QIcon(pixmap)) itemName = QtGui.QStandardItem(name.title()) itemHolder = QtGui.QStandardItem('ProgressBarItem') widget = QtGui.QProgressBar() widget.setValue(5 * (model.rowCount() + 1)) key = id(widget) self._widgets[key] = widget itemHolder.setData(key) model.appendRow([itemIcon, itemName, itemHolder]) self.setIndexWidget(model.indexFromItem(itemHolder), widget) class Window(QtGui.QWidget): def __init__(self): super(Window, self).__init__() self.treeView = TreeView() for name in 'red yellow green purple blue orange'.split(): self.treeView.addNewRow(name) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.treeView) if __name__ == '__main__':