2014-05-17 55 views
0

每个拖放操作(从一个QListWidget到另一个QListWidget)上的强度和复杂度声明错误都让我感到疯狂。我知道AssertionError是由一个类实例的属性引起的(类实例变量通过.setData()附加到QListWidget Item。其中一个属性与pickle不兼容,如果您能够解决此问题,我将不胜感激。以及如何高效地进行调试,到目前为止唯一的解决方案是逐个检查每个类的属性,将其设置为None,然后检查是否解决了问题,但这种方法非常繁琐且耗时。Qt和Pickle的声明错误疯狂

日后进行编辑:

调试后几个小时我已经缩小代码到它的最低限度它地复制我也遇到了同样的问题时,Qt控件(如QListWidget)无力。使用pickle来执行他们的任务。

一个简短的信息:ClassA和ClassB的的

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

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_()) 
+0

新手在这里...但你有任何字典里面的元组? – Roberto

+0

您是否检查过您的问题是否与此相同? http://stackoverflow.com/questions/4426981/python-pickle-dumps-assertionerror – Roberto

+0

我读过你提到的那个。有人说那里有一些旧的pickle协议无法处理的数据。要解决你的问题,请使用pickle.HIGHEST_PROTOCOL'。我不清楚如何在PyQt中设置'use pickle.HIGHEST_PROTOCOL'覆盖。有人知道吗? – alphanumeric

回答

1

Googl'ing为pyqt pickle protocol透露,有一个界面来设置的PyQt的咸菜协议:

QtCore.pyqtSetPickleProtocol() 
QtCore.pyqtPickleProtocol() 

参见:http://freecode.com/projects/pyqt/releases/354104

所以

QtCore.pyqtSetPickleProtocol(pickle.HIGHEST_PROTOCOL) 

可能做的伎俩。

+0

如果不会抛出'AttributeError:模块对象没有属性pyqtSetPickleProtocol',这可能是我的一个解决方案。 PyQt是否缺少'.pyqtSetPickleProtocol()'方法? – alphanumeric

+0

它在我的控制台上工作。你使用的是什么版本的PyQt?根据这些发行说明,该功能在4.10.1中介绍。 – sebastian

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)结果在错误消息中的重复。 所以,如果你可以没有循环参考,这可能是最简单的解决方法。

+0

不幸的是,我不能放弃我的代码中的循环引用。我严重依赖他们。你认为使用'.pyqtSetPickleProtocol()'方法可以改变吗? – alphanumeric