2014-05-17 78 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