Re: RE: PyQt and PyROOT

From: <WLavrijsen_at_lbl.gov>
Date: Thu, 11 Jan 2007 21:51:03 -0800 (PST)


Dear all,

couple of minor points: the warning about the missing QWidget dictionary can come from PyROOT, as it will attempt to create classes for all bases when a derived class is created (a class is not complete without its list of bases, as each (may) bring(s) in more functions, members, etc.). Further, a QWidget from a CINT dictionary and bound by PyROOT will not clash with one from PyQt. As far as python is concerned, these are two completely different classes. It will, however also consider them completely unrelated and you can't pass one where the other is expected. In concrete terms, one will be known as "ROOT.QWidget" and the other as "qt.QWidget" and occupy different places in memory.

Then, what I think is what you really want, is convincing either extension to take a class from the other by pointer. Unfortunately, I'm not that well versed in PyQt, but a Google "Lucky" search gives:

> Or try importing the sip module and "unwrapping" your widget instance:
>
> import sip
> addr = sip.unwrapinstance(my_widget)
>
> You'll get a Python integer that can either be passed as it is, or you
> can use it to create a voidptr object and obtain a PyCObject from that:
>
> ptr = sip.voidptr(addr)
> cobj = ptr.ascobject()

where module sip is from SIP, which is used to build PyQt, so I presume that you have it available (just give it a try, and let me know if it fails, and I'll install things myself to get some more info as needed).

That final "cobj" from your original widget is a so-called python CObject, aka opaque C pointer, aka "void*". PyROOT accepts these as drop-in for any interface that accepts pointers, so it should work for your TQtWidget ctor as well. PyROOT does not accept integers as drop-in for pointers, not even for void* (with the exception of the integer 0). Thus, something like:

   import sip
   cobj = sip.voidptr(sip.unwrapinstance(self.CentralWidget)).ascobject()    self.Canvas = TQtWidget(cobj)

is what I'd expect to work. It may be that the unwrapping is unnecessary and that the 'ascobject' method is directly available on the widget.

The converse would go with something like (this code is non-sensical, it's just for the idea how you'd do it, if so desired):

   import sip
   foo = sip.wrapinstance( ROOT.AddressOf(self.Canvas)[0], qt.QWidget )

Where the original TQtWidget is now seen as a qt.QWidget. (Code again from Google, haven't actually tried it out.)

What is going on is the following: AddressOf() returns a buffer object (I choose that b/c it's somewhat wider accepted than the CObject, and it is more easily to work with in python) that contains the address as a long. Thus, indexing it with [0], gives the void* value as a long integer. Then, wrapinstance does the inverse of unwrapinstances and binds this address to the qt.QWidget extension type.

Note that passing pointers around like this, is passing void*'s around in a way that is morally equivalent to reinterpret_cast<>. Consequently, there are no casts done (i.e. no pointer offsets for base classes). This is ok, if the type expected and the type that you have, have 0 offset (e.g. when they are the same time, or when they have a simple inheritance structure). Otherwise, if both the base and the derived class have a CINT dictionary, you can use TClass to perform the casting, though.

Hope that helps. Please let me know if any part requires any further clarification, or if you don't have module sip available.

Best regards,

           Wim

--
Wim.Lavrijsen_at_cern.ch   --   WLavrijsen_at_lbl.gov   --   www.lavrijsen.net

"Stop making excuses for your software."    --first step towards quality
   "GIGO is not a valid design pattern."         --corollary
Received on Fri Jan 12 2007 - 06:51:20 CET

This archive was generated by hypermail 2.2.0 : Fri Jan 12 2007 - 17:50:00 CET