[PyKDE] Re: Bug with QScrollView viewport binding

Phil Thompson phil at riverbankcomputing.co.uk
Wed Jun 29 16:42:01 BST 2005


On Wednesday 29 June 2005 4:07 pm, Giovanni Bajo wrote:
> Phil Thompson <phil at riverbankcomputing.co.uk> wrote:
> >>> Yes - but they aren't in existence at the same time.
> >>> [...]
> >>> Using a temporary name to keep a reference to sv.viewport() solves the
> >>> problem.
> >>
> >> Then you have the inverse problem:
> >>
> >> ----------------------------------------------
> >> from qt import *
> >>
> >> app = QApplication([])
> >> sv = QScrollView(None)
> >> w = QWidget(sv.viewport())
> >>
> >> p = w.parent()
> >> print sv.viewport().width()
> >> ----------------------------------------------
> >> Traceback (most recent call last):
> >>   File "D:\Work\caligola3d\src\pyqtbug3.py", line 9, in ?
> >>     print sv.viewport().width()
> >> AttributeError: width
> >>
> >> which is wrong because viewport() is supposed to return a QWidget
>
> pointer.
>
> > It sees that it has already been wrapped (as a QObject) and just returns
>
> an
>
> > extra reference. It doesn't try to retype the existing wrapper, or create
>
> a
>
> > new wrapper to the same C++ instance with the more specific type.
>
> I understand the technical problem, but I believe it is a right expectation
> that any call to QScrollView.viewport() return a QWidget, as documented.
> The fact that thousands lines away I happen to have a QObject reference to
> the same object should not thoeretically make QScrollView.viewport() break
> its contract.

Understood - but I'm concerned about possible unforeseen implications. Of the 
two obvious options...

1) Re-type the existing object when the more specific type is known. This is 
probably safe to do as far as the internals are concerned - but the idea of a 
Python object changing type under your feet sounds horrible.

2) Generate a new wrapper to the same C++ object with the more specific type. 
This has obvious problems with ownership (who calls the C++ dtor?), and 
things like "is" would fail. This is a real can of worms.

> Notice that there is *never* a need for downcast in PyQt, and this would be
> a sole example.

Some PyKDE uses have this requirement - hence sip.cast().

> For instance: 
> ----------------------------------
>
> >>> from qt import *
> >>> app = QApplication([])
> >>> class Foo(QWidget):
>
> ...     k = 1
> ...
>
> >>> f = Foo(None)
> >>> w = QWidget(f)
> >>> w.parent().k
>
> 1
>
> >>> print w.parent()
>
> <__main__.Foo object at 0x00813660>
> ----------------------------------
> In this case, PyQt was *even* able to recreate a wrapper of type Foo from
> the parent call. I assume because the actual underlying type is something
> that PyQt knows about (Foo) instead of an internal Qt type (as for the case
> of the scrollview's viewport).

No, it's because f keeps the wrapper alive so it is found by w.parent().

> It is surprising that the call to parent() in the original example is not
> able to return a QWidget. The common PyQt behaviour is always to return a
> reference to most down-casted type. So I would expect the parent() to
> return *at least* a QWidget whenever the object is a QWidget.

The most down-cast type, yes - but *only* if it is a know type. Otherwise it 
resorts to the base type.

> Either that, or always retry to downcast any reference you get from the
> internal SIP map of existing python refernces. QScrollView.viewport()
> really *is* supposed to return *at least* a QWidget.

Yes - rather than see if the type *is* a known type, see if the type is 
*derived* from a known type. Or maybe do the second only if the first fails 
(for speed and to ensure it doesn't break existing behaviour).

Phil




More information about the PyQt mailing list