PyQt: dar padre al crear un widget?

Supongamos que quiero crear un cuadro de diálogo, un elemento secundario de mi progtwig principal:

from PyQt4 import QtGui, QtCore class WizardJournal(QtGui.QDialog): def __init__(self, parent): super(WizardJournal, self).__init__(parent) self.parent = parent self.initUI() def initUI(self): self.parent.wizard = QtGui.QWidget() self.ok_button = QtGui.QPushButton("OK", self) self.vbox_global = QtGui.QVBoxLayout(self) self.vbox_global.addWidget(self.ok_button) self.paret.wizard.setLayout(self.vbox_global) self.parent.wizard.show() if __name__ == '__main__': app = QtGui.QApplication(sys.argv) parent = QtGui.QWidget() obj = WizardJournal(parent) sys.exit(app.exec_()) 

Este cuadro de diálogo será abierto y cerrado por mi progtwig principal. Lo que es mejor con respecto al consumo de memoria:

  • self.ok_button = QtGui.QPushButton("OK", self)
  • self.ok_button = QtGui.QPushButton("OK")

Básicamente, me gustaría saber si debo mencionar el widget principal cuando creo un widget. Cuando cierre este cuadro de diálogo, ¿se liberará el botón Aceptar de la memoria si no mencioné el widget principal cuando lo creé?

Dada la forma en que está estructurado actualmente su ejemplo, ni el diálogo ni ninguno de sus widgets secundarios se eliminarán cuando se cierre.

Puedes ver esto cambiando el final del ejemplo para que se vea así:

 app.exec_() print('\n'.join(repr(w) for w in app.allWidgets())) 

lo que dará una salida como esta (una vez que se cierre el diálogo):

 <__main__.WizardJournal object at 0x7fcd850f65e8>     

En PyQt, debe tener en cuenta que puede haber dos tipos de referencia para un objeto: uno en el lado de Python (el objeto envoltorio de PyQt) y otro en el lado de C ++ (el objeto Qt subyacente). Por lo tanto, para eliminar completamente un objeto, debe eliminar todas estas referencias.

En general, Qt no elimina objetos a menos que usted lo indique explícitamente. Esto es algo que debe tener en cuenta al crear diálogos con un padre, porque de lo contrario es muy fácil producir una pérdida de memoria. Es común ver el código escrito así:

 def openDialog(self): dialog = MyDialog(self) dialog.show() 

Lo que parece inofensivo a primera vista, pero el método creará un nuevo diálogo cada vez que se llame, y Qt terminará aferrándose a cada uno de ellos (debido a la referencia parent en el lado de C ++). Una forma de evitar esto es volver a escribir el método para que solo mantenga una referencia en el lado de Python:

 def openDialog(self): self.dialog = MyDialog() self.dialog.show() 

Pero, ¿qué hacer con un diálogo modal, que debe tener un padre? En ese caso, podría inicializar la clase de diálogo así:

 class MyDialog(QtGui.QDialog): def __init__(self, parent): super(MyDialog, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) 

Y ahora, Qt eliminará automáticamente el diálogo cuando se cierre, y también eliminará recursivamente todos sus objetos secundarios. Esto dejará atrás un objeto envoltorio PyQt vacío, que (eventualmente) será eliminado por el recolector de basura Python.

Entonces, para su ejemplo en particular, creo que lo reescribiría para que se vea algo así:

 import sys from PyQt4 import QtGui, QtCore class WizardJournal(QtGui.QDialog): def __init__(self, parent): super(WizardJournal, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.initUI() def initUI(self): self.ok_button = QtGui.QPushButton("OK", self) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.ok_button) self.show() if __name__ == '__main__': app = QtGui.QApplication(sys.argv) parent = QtGui.QWidget() obj = WizardJournal(parent) app.exec_() print('\n'.join(repr(w) for w in app.allWidgets())) 

La clase de diálogo ahora es completamente autónoma, y ​​solo hay una referencia de python externa a la instancia. (Si necesita acceder al widget principal desde la clase de diálogo, puede usar self.parent() ).

PD: cuando los widgets se agregan a un diseño, se volverán automáticamente a los widgets de nivel superior que eventualmente contengan el diseño. Por lo tanto, estrictamente hablando, no es necesario establecer explícitamente un padre para dichos widgets en su código.