2016-08-12 63 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)。

如果我不清楚或不够准确,请让我知道。
希望它有帮助。
干杯。