[PyKDE] PyQt4 Questions

Giovanni Bajo rasky at develer.com
Sat Mar 18 15:29:00 GMT 2006

Detlev Offenbach <detlev at die-offenbachs.de> wrote:

> I have a dialog, that creates a new dialog and shows it. The code is like
> self.dlg = MyDialog(self)
> dlg.show()

MyDialog is a QObject, and it is constructed as child of self. Its lifetime
becomes bound to the lifetime of "self", pretty much like every other child
of self (including labels, buttons, etc.).

> This code is part of a slot. Whenever this code is hit, a new dialog is
> created with destroying the old one. I thought, that the garbage collector
> should take care of deleting the old one.

No, because like any other QObject, its lifetime is bound to its parent,
*irrespective* of the lifetime of the Python object (which can be destroyed
and recreated on demand). Think of how many widgets you (probably) create to
compose a dialog and for which you do *not* keep a Python reference.

> Same thing happens with nonmodal dialogs spawned from the QMainWidget.
> closing the application, I have to close every single dialog, that was
> displayed via the show() method, individually.

The point is that PyQt *specifically* implements a workaround for QDialog
and QPopupMenu when used as *modal* dialogs. If you run the exec_loop()
method (and thus request modal behaviour), their lifetime semantic is
explicitally changed and becomes bound to the *Python* reference. This
allows to write Python code to use modal dialogs which works

For modeless dialogs, you're out of luck. There are at least a couple of
ways to do what you want:

* Explicitally delete the widget before constructing the new one. There is
no equivalent of "delete dlg" in Python, so the common way is to call the
deleteLater() method. This is usually enough. Notice that you can force the
deleteLater() message to be immediately processed by doing:
qApp.sendPostedEvents(widget, QEvent.DeferredDelete). Usually you don't need
this, though, and waiting till the next event loop is good enough.

* Tell SIP that you want the lifetime of the dialog to be bound to the
Python object. This is spelled: "sip.transferback(self.dlg)". You need to
import sip, of course. This is *exactly* what PyQt does when you call the
exec_loop() method in QDialog and QPopupMenu.

> Additionally I have seen this strange behavior. If I create the dialog
> with self as a parent, the dialog containing the slot is put behind all
> other windows.
> Another observation is, that the newly generated dialog (using the above
> code) is put centered on top of the generating dialog. I expected the
> manager to take care of the placement.
> The last observation is, that the generating dialog is always behind the
> generated dialog. I cannot bring it into the foreground.

I see these behaviours with Qt under Windows, but I didn't bother
investigated, and I blamed it on Windows' window manager. I don't think PyQt
has anything to do with either, though. Maybe there is a workaround for the
latter you mentioned (in the WFlags) but I don't recall.
Giovanni Bajo

More information about the PyQt mailing list