2016-08-12 64 views
1

我遇到了非Qt對象超出範圍並被Python收集垃圾的問題。在下面的通用示例中,我在單擊一個按鈕時創建一個對象,並在單擊另一個按鈕時使用該對象。第一個按鈕的插槽完成執行後,該對象被垃圾收集。對象超出範圍,並在PySide/PyQt中被垃圾收集

# Started from http://zetcode.com/gui/pysidetutorial/firstprograms/ and 
# connections program from chap 4 of Summerfield's PyQt book 

import sys 
from PySide import QtGui 


def createThingy(): 
    thing1 = thingy("thingName", 3, wid) 
    lbl1.setText(thing1.name + " created.") 
    return 


def updateNum(): 
    lbl1.setText("number: " + str(thing1.number)) 

    return 


class thingy(object): 
    def __init__(self, name, number, mainWindow): 
     self.name = name 
     self.number = number 

    def func1(self): 
     return "Something to return" 

    def rtnNum(self): 
     return "Num: " + str(self.number) 

app = QtGui.QApplication(sys.argv) 

wid = QtGui.QWidget() 
wid.resize(250, 150) 
wid.setWindowTitle('Example') 

btn1 = QtGui.QPushButton("Create thingy") 
btn2 = QtGui.QPushButton("Number") 
lbl1 = QtGui.QLabel("---") 

vlayout = QtGui.QVBoxLayout() 
vlayout.addWidget(btn1) 
vlayout.addWidget(btn2) 
vlayout.addWidget(lbl1) 
wid.setLayout(vlayout) 

btn1.clicked.connect(createThingy) 
btn2.clicked.connect(updateNum) 

wid.show() 
wid.raise_() 
sys.exit(app.exec_()) 

這種行爲是PySide陷阱網頁,https://wiki.qt.io/PySide_Pitfalls,以及問題「巨蟒PySide(內部C++對象已刪除)」 https://stackoverflow.com/a/5339238/2599816(這個問題並沒有真正回答,因爲我的問題上提到作者的解決方案是爲了避免這個問題)。

因爲該對象不是Qt對象,所以將它傳遞給父對象不是一個可行的選項。此外,我不想在程序開始時創建對象,因爲其他問題/答案在其他地方提出過(無法再找到它們的鏈接)。此外,不應該修改該對象來解決這個問題,而是應該在GUI中實現該解決方案,即保持該對象通用以用作其他程序中的庫。

  • 如何使對象成爲我的窗口或小部件的屬性,如陷阱頁面所示?
  • 使它成爲窗口/小部件的屬性是一個選項,是否有更好的設計/更優雅的解決方案/最佳實踐使用?

感謝您的幫助。

回答

1

創建的QWidget一個子類,以保持所有子對象的屬性:

import sys 
from PySide import QtGui 

class Widget(QtGui.QWidget): 
    def __init__(self, parent=None): 
     super(Widget, self).__init__(parent) 
     self.resize(250, 150) 
     self.setWindowTitle('Example') 

     self.btn1 = QtGui.QPushButton("Create thingy") 
     self.btn2 = QtGui.QPushButton("Number") 
     self.lbl1 = QtGui.QLabel("---") 

     vlayout = QtGui.QVBoxLayout() 
     vlayout.addWidget(self.btn1) 
     vlayout.addWidget(self.btn2) 
     vlayout.addWidget(self.lbl1) 
     self.setLayout(vlayout) 

     self.btn1.clicked.connect(self.createThingy) 
     self.btn2.clicked.connect(self.updateNum) 

    def createThingy(self): 
     self.thing1 = thingy("thingName", 3, wid) 
     self.lbl1.setText(self.thing1.name + " created.") 

    def updateNum(self): 
     self.lbl1.setText("number: " + str(self.thing1.number)) 

class thingy(object): 
    def __init__(self, name, number, mainWindow): 
     self.name = name 
     self.number = number 

    def func1(self): 
     return "Something to return" 

    def rtnNum(self): 
     return "Num: " + str(self.number) 

if __name__ == '__main__': 

    app = QtGui.QApplication(sys.argv) 
    wid = Widget() 
    wid.show() 
    sys.exit(app.exec_()) 
1

它正在收集垃圾,因爲一旦功能執行結束範圍丟失。您需要保存的參考,有這樣做的方法有兩種:

  1. 保存對象在一個全局變量,所以它不會被GC回收,也留在其他功能進行訪問。
  2. 將所有內容包裝在QWidget實現中,並將創建的對象保存在widget對象中(通過self)。

如果我不清楚或不夠準確,請讓我知道。
希望它有幫助。
乾杯。