[PyKDE] Issue with QDialog and lifetime

Phil Thompson phil at riverbankcomputing.co.uk
Thu Jul 7 13:45:38 BST 2005


> Phil Thompson <phil at riverbankcomputing.co.uk> wrote:
>
>>> 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.
>
> Yeah, I understand. Better ideas?

1. Either add an optional parameter to exec_loop() which does the transfer
or have exec_loop_and_transfer() (or something less of a mouthful). At
least that way it won't break existing code.

2. Implement sip.destroy() which calls the C++ dtor of its argument. (This
is on the TODO list anyway.)

3. Use sip.transfer().

Either way, I don't think it can be done (to my satisfaction)
transparently. The programmer is going to have to be aware of the issue
and explicitly deal with it.

Phil




More information about the PyQt mailing list