[PyKDE] Issue with QDialog and lifetime

Phil Thompson phil at riverbankcomputing.co.uk
Thu Jul 7 09:22:02 BST 2005


> Phil Thompson <phil at riverbankcomputing.co.uk> wrote:
>
>>>>>> Does anyone see a potential problem with exec_loop() transferring
>>>>>> ownership of the dialog instance back to Python?
>>>>>
>>>>> Well, which C++ API would you intend to call to achieve this? We
>>>>> still
>>>>> need the QDialog to keep its parent widget because it is the widget
>>>>> on
>>>>> which the dialog is modal.
>>>>
>>>> [...]
>>>> You should be able to test this with sip.transfer( dlg, 0 ) just
>>>> before dlg.exec_loop().  Ultimately, a sipTransfer() should be added
>>>> to the %MethodCode for exec_loop().
>>>
>>> Yeah this works very well!
>>> Phil, what do you think of this? It solves a nasty problem.
>>
>> Could somebody summarise the original problem for me, and why this is
>> required?
>
> The problem is that the idiomatic way of using modal dialogs in C++ is to
> create local variables, which gets destroyed when their scope finishes
> (when
> the function exits). Moreover, the dialogs have to be children of whatever
> widgets they are modal over (e.g. the main window).
>
> This has no direct translations in PyQt. If you do:
>
> def slotWhatever(self):
>    dlg = MyModalDialog(self)
>    if dlg.exec_loop() == QDialog.Accepted:
>        return dlg.data()
>    return None
>
> you are leaking "dlg" because its lifetime is bound to its parent. The
> current common workaround is something like:
>
> def slotWhatever(self):
>    dlg = MyModalDialog(self)
>    try:
>        if dlg.exec_loop() == QDialog.Accepted:
>            return dlg.data()
>        return None
>    finally:
>        dlg.deleteLater()
>
> which is ugly and error-prone (you have to remember to do it).
>
> James proposed this solution:
>
> def slotWhatever(self):
>    dlg = MyModalDialog(self)
>    sip.transfer(dlg, 0)
>    if dlg.exec_loop() == QDialog.Accepted:
>        return dlg.data()
>    return None
>
> and then proposed to hardcode the transfer() call within the %MethodCode
> for
> QDialog.exec_loop. I'll remember you that exec_loop is called only for
> modal
> dialogs, while for modeless dialogs show() is called.

I'm uncomfortable with this for two reasons...

1. It's inconsistent behaviour. As there are things you need to be aware
of when using PyQt (particularly with regard to ownership) I think it's
important to have consistency in those things.

2. It creates the strong possibility of a seg fault for those (existing)
applications that don't follow the common idiom.

What's wrong with just passing WDestructiveClose in the dialog's ctor call
to QDialog.__init__()? I've no problem with adding this issue to the
documention.

Phil




More information about the PyQt mailing list