2016-11-06 113 views
1

此问题与此主题中的问题类似Preserve QStandardItem subclasses in drag and drop但存在问题,我无法找到一个好的解决方案。这个话题部分帮助,但在更复杂的任务上失败。QT,Python,QTreeView,自定义小部件,setData - 拖放后失去引用

当我在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 

我能想到的解决这个问题的办法是遍历整个树形递归超过每行/儿童和名称匹配更新项目....问题是,我将令人耳目一新树状每0.5秒并有500 +行,每个5-15项。意思是......我不认为这样会很快/很有效......如果我想每0.5秒循环5 000个物品......

有人可以建议我怎么解决这个问题吗?也许我可以编辑dropEvent,因此它不会复制/粘贴项目,而是移动项目....这样我就不会丢失我的对象在数组中

回答

1

Qt只能序列化可存储在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__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(500, 150, 600, 400) 
    window.show() 
    sys.exit(app.exec_()) 
+0

我曾与字典和ID的作品类似的东西,但是当我得知我拖/放,因为setIndexWidget提出这是在数组对象也树状当QT复制/过去也删除了该项目。造成错误 - 除非我做了其他错误。在任何情况下,我想要做的就是在'dropEvent()超级(treeView,self).dropEvent(event)self.treeView.reInitializeView()'之后'所以我会回味地遍历每个小部件,并重新附加新的进度条给他们。它适用于90%的问题,但是它也做的是复制这个项目: - (在drop event中最后一个函数是什么? – Dariusz

+0

@Dariusz。对我来说,这一切都很好。我添加了一个完整的演示脚本我的答案 – ekhumoro

+0

它是半工作的,一旦你拖动0项到另一个0项,子项将有ProgressBarItem文本而不是进度。我最终做的是在进度条中指定一个函数,该函数在数组中寻找数据的特定位置。它在我移动项目等时起作用,因为它始终保留数组中的数据位置的ID。我总是通过dragEvent上的update函数重新连接这些进度条。在旁注中,如果我按项目1-2拖动-3(不是0)在另一个项目之上。项目行消失了,也许你知道如何限制?https://youtu.be/L6qLuC2dmhE例子 – Dariusz