Qt和Pickle的断言错误疯狂

时间:2014-05-17 01:28:55

标签: python pyqt pickle

我的每一次拖放(从一个QListWidget到另一个QListWidget)的强度和复杂性断言错误让我变得疯狂。我知道AssertionError是由类实例的一个属性引起的(类实例变量通过.setData()附加到QListWidget项。其中一个属性与pickle不兼容。如果你感谢我启发我如何处理这个问题以及如何有效地调试它。到目前为止,唯一的解决方案是逐个遍历每个类属性,将其设置为None,然后检查是否解决了Assertion Error问题。但这种方法非常繁琐且耗时。

以后编辑:

经过几个小时的调试后,我将代码缩减到最低限度。当Qt小部件(例如QListWidget)无法使用pickle执行任务时,它会严重复制我遇到的同一问题。

简短信息:

声明了ClassA和ClassB的两个实例。然后instB存储在instA属性中。反之亦然:instA存储在instB属性中。其余的很简单:将instA via .setData()分配给ListWidget项。 Drag'nDrop项目导致pickle失败。 请告知将来如何避免这种情况。是什么导致它。如果有可能的方案来解决它。

enter image description here


from PyQt4 import QtCore, QtGui

class Base(dict):
    def __init__(self):
        super(Base, self).__init__()

    def setInstB(self, instB):
        self['instB']=instB

class ClassA(Base):
    def __init__(self):
        super(ClassA, self).__init__()  

class ClassB(Base):
    def __init__(self):
        super(ClassB, self).__init__()

    def setInstA(self, instA):
        self.instA=instA

instA=ClassA()
instB=ClassB()

instA.setInstB(instB)
instB.setInstA(instA)


class Dialog(QtGui.QMainWindow):
    def __init__(self, instA):
        super(QtGui.QMainWindow,self).__init__()

        widget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout()
        widget.setLayout(layout)       

        self.listA=QtGui.QListWidget()
        self.listA.setAcceptDrops(True)
        self.listA.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.listA.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)


        listItem=QtGui.QListWidgetItem(str(id(instA) ) )
        listItem.setData(QtCore.Qt.UserRole, instA)
        self.listA.addItem(listItem)

        self.listB=QtGui.QListWidget()
        self.listB.setAcceptDrops(True)
        self.listB.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.listB.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)

        layout.addWidget(self.listA)
        layout.addWidget(self.listB)
        self.setCentralWidget(widget)

app = QtGui.QApplication(sys.argv)
dialog=Dialog(instA)
dialog.show()
dialog.resize(480,320)
sys.exit(app.exec_())

2 个答案:

答案 0 :(得分:1)

for pyqt pickle protocol的Googl揭示了,设置PyQt的泡菜协议的界面:

QtCore.pyqtSetPickleProtocol()
QtCore.pyqtPickleProtocol()

请参阅:http://freecode.com/projects/pyqt/releases/354104

所以

QtCore.pyqtSetPickleProtocol(pickle.HIGHEST_PROTOCOL)

可能会成功。

答案 1 :(得分:0)

似乎问题是循环引用 - instA引用instB,反之亦然。 以下适用于我:

class Base(dict):
    def __init__(self):
        super(Base, self).__init__()

    def setInstB(self, instB):
        self['instB']=instB

class ClassA(Base):
    def __init__(self):
        super(ClassA, self).__init__()

class ClassB(Base):
    def __init__(self):
        super(ClassB, self).__init__()

    def setInstA(self, instA):
        self.instA=instA

if __name__ == '__main__':

    import pickle

    instA=ClassA()
    instB=ClassB()

    instA.setInstB(instB)
    # omit the cyclic reference
    #instB.setInstA(instA)

    pickle.dumps(instA)

评论instB.setInstA(instA)会导致您的错误消息被复制。 因此,如果您可以不使用循环引用,这可能是最简单的解决方法。