[PyKDE] embedding PyQt in a c++ app

Christoph Wiedemann wiedeman at gmx.net
Mon Aug 2 18:18:00 BST 2004


> Hi.
> 
> On Thu, Jul 29, 2004 at 05:21:25PM +0200, Christoph Wiedemann wrote:
> > Hello,
> > 
> > i have problems to embed PyQt in a c++ application. Since the
> application
> > uses threads and multiple python interpreters, i must ensure that the
> > correct thread state is set and the GIL is locked, whenever the python
> API
> > is used. I do that with the
> > 
> >   PyEval_RestoreThread(threadState);
> > 
> > and
> > 
> >   PyEval_SaveThread();
> > 
> > methods. This works fine, as long as i don't use widgets created with
> PyQt,
> > because there are many "callbacks" (virtual methods), e.g.
> mousePressEvent,
> > which are called directly from PyQt. 
> > 
> 
> I had the same problem. But since this wasn't a major issue for my
> project, I gave up without investigating. But I am interested in the
> solution.
> 
> > Is there any way to force PyQt to acquire the GIL before those virtual
> > methods are called?
> > 
> > Hmm, this wouldn't solve the issue with multiple interpreters; each
> > interpreter has its own thread state, which must be restored before
> using
> > the API. 
> 
> I do it something like that:
> 
>   PyThreadState* _pyThreadState;
>   _pyThreadState = Py_NewInterpreter();
> 
> then later
> 
>   PyEval_AcquireLock();
>   PyThreadState_Swap(_pyThreadState);
> 
>   ... some python stuff ...
> 
>   PyThreadState_Swap(NULL);
>   PyEval_ReleaseLock();
> 
> and when I'm done
> 
>   PyEval_AcquireLock();
>   PyThreadState_Swap(_pyThreadState);
> 
>   Py_EndInterpreter(_pyThreadState);
> 
>   PyThreadState_Swap(NULL);
>   PyEval_ReleaseLock();

I think i got a solution for that. The trick is to call 

PyThreadState_Swap(threadState);

in the QWidget.event function (when this function is called, the GIL is
already hold). This is done by some c-extension stuff, so i can do the
following:

class MyWidget(QWidget):
    def event(self, e):
        support.swapThreadState() # calls appropriate c-function 
        return QWidget.event(self, e)

and everything works out fine (at least for instances of MyWidget). 

I'm still not sure, if i can apply the same trick for built-in widgets; i
don't need them by now, but maybe later. I guess i can't do

b = QButton()
oldEvent = b.event
def myEvent(self, e): 
   support.swapThreadState()
   return oldEvent(self, e)
b.event = myEvent

??

Maybe it's enough to put all builtin-widgets into a self-written container
widget with the event handler installed...

Thanks,
Christoph




More information about the PyQt mailing list