2016-11-06 115 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