2013-05-30 30 views
6

我有一个小部件,在它被销毁之后必须进行一些手动清理(停止某些线程)。然而由于某种原因,小部件的“被破坏”信号没有被触发。我做了这个小例子来证明问题。Widget的“已销毁”信号没有被触发(PyQT)

import sys 
from PyQt4 import QtGui 

class MyWidget(QtGui.QWidget): 
    def __init__(self, parent): 
     super(MyWidget, self).__init__(parent) 

     def doSomeDestruction(): 
      print('Hello World!') 

     self.destroyed.connect(doSomeDestruction) 


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

     self.widget = MyWidget(self) 

app = QtGui.QApplication(sys.argv) 
window = MyWindow() 
window.show() 
ret = app.exec_() 
sys.exit(ret) 

我希望它打印出“Hello World!”当主窗口关闭时。但是,它不打印任何东西。

回答

5

经过几次尝试,我发现它 的作品,如果你在课堂外宣布 doSomeDestruction(见底部)
但我不知道为什么。 正如写在this的答案,这是因为At the point destroyed() is emitted, the widget isn't a QWidget anymore, just a QObject (as destroyed() is emitted from ~QObject)
这意味着当你的函数被调用时,如果你在类中写入它,它已经被删除。 (也期待here在QT-interest邮件列表:Ok , I am sorry for stupid question. The signal is emitted, but the slot is not called for the obvious reason, that is because object is already deleted.

编辑:我发现了两种方式让它真正发挥作用:

  1. ret = app.exec_()后添加一个简单的del window
  2. 设置WA_DeleteOnClose属性在主窗口(未微件):
    在程序的顶部:

    from PyQt4 import QtCore 
    

    的改变__init__功能:

    class MyWindow(QtGui.QMainWindow): 
        def __init__(self): 
         super(MyWindow, self).__init__() 
         self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) 
         self.widget = MyWidget(self) 
    
+0

您能否与我共享打印Hello World的代码?我试图根据你的指示编辑代码,但它仍然不起作用。 http://pastebin.com/ZCgteHu4 – Scintillo

+0

这很奇怪。我的代码唯一的区别是,doSomeDestruction在两个类之间定义。但是现在我发现它有时也是有效的。还有['gc.collect'](http://docs.python.org/3.3/library/gc.html#gc.collect),但它没有效果。我希望我们/某人可以找到一种方法使其工作。 – TobiMarg

+0

看到我更新的答案。我应该现在工作。 (不管在哪里定义了doSomeDestruction) – TobiMarg

0

的python类实例(或至少是pyqt < - > qt链接)在destroyed发射时不存在d。您可以通过在类上设置destroyed处理程序为staticmethod来解决此问题。这样,当发出destroyed信号时,python方法仍然存在。

class MyWidget(QWidget): 

    def __init__(self, parent): 
     super(MyWidget, self).__init__(parent) 
     self.destroyed.connect(MyWidget._on_destroyed) 

    @staticmethod 
    def _on_destroyed(): 
     # Do stuff here 
     pass 

如果您需要特定的类实例的信息,您可以使用functools.partial和实例__dict__来传递信息的销毁方法。

from functools import partial 

class MyWidget(QWidget): 

    def __init__(self, parent, arg1, arg2): 
     super(MyWidget, self).__init__(parent) 
     self.arg1 = arg1 
     self.arg2 = arg2 
     self.destroyed.connect(partial(MyWidget._on_destroyed, self.__dict__)) 

    @staticmethod 
    def _on_destroyed(d): 
     print d['arg1'] 
+0

为什么不只是:'self.destroyed.connect(lambda:打印(自.__字典__))'?或者像OPs原始示例中那样使用闭包。 (这个例子不起作用的唯一原因是因为这些小部件从未被明确删除过)。 – ekhumoro

+0

@ekhumoro你通常比单一打印做更多的实质性操作。'lambda'只支持单个语句。通常情况下,你会与一些其他库和对象进行交互,这些对象在销毁时需要清理。有趣的是,我甚至没有注意到最初的例子是使用闭包而不是类实例方法。我认为封闭也会起作用。 –

+0

我想我应该问:使用'staticmethod'的具体优点是什么?为什么不只是使用* any *普通函数(不一定是闭包),而不是实例方法? – ekhumoro

相关问题