Re: [PyKDE] Re: Bug with QScrollView viewport binding
On Wednesday 29 June 2005 3:21 pm, Giovanni Bajo wrote: Phil Thompson [EMAIL PROTECTED] 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. Phil ___ PyKDE mailing listPyKDE@mats.imk.fraunhofer.de http://mats.imk.fraunhofer.de/mailman/listinfo/pykde
Re: [PyKDE] Re: Bug with QScrollView viewport binding
Phil Thompson [EMAIL PROTECTED] 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. Notice that there is *never* a need for downcast in PyQt, and this would be a sole example. 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). 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. 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. -- Giovanni Bajo ___ PyKDE mailing listPyKDE@mats.imk.fraunhofer.de http://mats.imk.fraunhofer.de/mailman/listinfo/pykde
Re: [PyKDE] Re: Bug with QScrollView viewport binding
On Wednesday 29 June 2005 4:07 pm, Giovanni Bajo wrote: Phil Thompson [EMAIL PROTECTED] 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 ___ PyKDE mailing listPyKDE@mats.imk.fraunhofer.de http://mats.imk.fraunhofer.de/mailman/listinfo/pykde
Re: [PyKDE] Re: Bug with QScrollView viewport binding
Phil Thompson [EMAIL PROTECTED] wrote: 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. I don't like either as well. The current logic, quoting you, is: The most down-cast type, yes - but *only* if it is a know type. Otherwise it resorts to the base type. Maybe this could be adjusted to: automatically cast-down to the most derived type which is known. This way, calling parent() for QWidget's will always create at least a QWidget, since all widgets' parents are widgets themselves. Also, we would get a QWidget for the viewport too (which is derived from QWidget, in fact), and this would solve the problem. This is also what you say here, assuming I understood: 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). so looks like we agree on this solution. 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(). I would like to see some. Giovanni Bajo ___ PyKDE mailing listPyKDE@mats.imk.fraunhofer.de http://mats.imk.fraunhofer.de/mailman/listinfo/pykde