QT,Python,QTreeView,自定义小部件,setData - 拖放后丢失引用

时间:2016-11-06 17:38:48

标签: python qt qtreeview qstandarditemmodel qstandarditem

这个问题与本主题Preserve QStandardItem subclasses in drag and drop中的问题类似,但问题是我无法找到一个好的解决方案。该主题部分有所帮助,但在更复杂的任务中失败。

当我在QTreeView中创建一个项目时,我将该项目放入我的数组中但是当我使用拖放时,该项目被删除,我无法再访问它。我知道它是因为拖放复制项目而不是移动它所以我应该使用setData。我不能将setData作为一个对象,因为即使这样,对象也会被复制,我会失去对它的引用。

这是一个例子

#!c:\Dwimperl\perl\bin\perl.exe

use strict;
use warnings;

use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);
print "Content-type: text/html\n\n";

#read form input from user
my $userinput = <STDIN>;
my $low = param ('lowest');
my $high = param ('highest');


foreach (my $userinput < 100){
print "$low && $high" ;}

如果我没有移动小部件,上面的代码就可以了。第二次我拖放我失去参考我失去了所有项目的更新,我崩溃了。

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])

我能想到修复这个问题的方法是在每个行/子项和名称匹配更新项上递归遍历整个树视图....问题是我每0.5秒刷新一次树视图并且有500+每行5-15项。意思是......我不认为这会非常快/有效...如果我想每0.5秒循环超过5 000件......

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

1 个答案:

答案 0 :(得分: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_())