[PyQt] Overriding (hooking) an event() function: QWidget vs QGraphicsWidget

Phil Thompson phil at riverbankcomputing.com
Sat Jan 2 13:07:20 GMT 2010


On Sat, 2 Jan 2010 15:38:00 +0300, z <zoomer.gm at gmail.com> wrote:
> 2010/1/2 Phil Thompson <phil at riverbankcomputing.com>:
>> On Sat, 2 Jan 2010 13:15:52 +0300, z <zoomer.gm at gmail.com> wrote:
>>> Hello everybody, and happy new year!
>>> to the point:
>>> In python it is possible to override some method of an instance,
>>> assigning to a "instance.methodname" a new value (which must be
>>> callabe with the same number of arguments, to be useful)
>>> For example i'd like to intercept events, coming to some widget,
>>> having this widget instance. It is easy to achieve, if i define this
>>> widget's class myself, and therefore can redefine event() method in
>>> class definiion. But suppose, that i just providing an interface for
>>> using by other parties. One, who using it only give me an instance,
>>> which class definition i can not control.
>>> This is an example program, which defines a hook function, and
>>> replaces instance's original event() method with it (for the start we
>>> will see how it works for QGraphicsWidget):
>>> ###########################
>>> from PyQt4 import QtGui, QtCore
>>>
>>> app = QtGui.QApplication(sys.argv)
>>>
>>> # suppose this class is defined somewhere else
>>> class Target(QtGui.QGraphicsWidget):
>>>     def __init__(self):
>>>         QtGui.QGraphicsWidget.__init__(self)
>>>
>>> target = Target()
>>> target.show()
>>>
>>> eventOrig = target.event
>>>
>>> # intercept function, which just prints incoming event type, and
>>> passes further processing to original event()
>>> def eventHook(ev):
>>>     print 'HOOK', ev.type()
>>>     return eventOrig(ev)
>>>
>>> target.event = eventHook
>>>
>>> # Let's trigger an event()
>>> QtGui.QApplication.postEvent(target,
>>> QtCore.QEvent(QtCore.QEvent.LayoutRequest))
>>> target.resize(200,200)
>>>
>>> sys.exit(app.exec_())
>>> ############################
>>>
>>> Of course, it is not fully complete and sane code, but it
>>> demonstrates, that this approach works fine. This is console output of
>>> this program:
>>> ###########
>>> HOOK 181
>>> HOOK 76
>>> ############
>>> (181 is QEvent.GraphicsSceneResize, and 76 is layoutrequest ) So it
>>> works for QGraphicsWidget.
>>> But it does not work for QWidget. i.e. if the class is defined as:
>>> ############
>>> class Target(QtGui.QWidget):
>>>    def __init__(self):
>>>        QtGui.QWidget.__init__(self)
>>> #############
>>> Nothing appears on output at all. But the program runs flawlessly,
>>> (and shows main window, containing this widget)
>>>
>>> So the question is: what's the difference? Why it works for
>>> QGraphicsWidget, but not QWidget? Is it some peculiarities of Qt event
>>> processing? Or is it PyQt? Or is it my system config or installed
>>> software gone wrong?
>>>
>>> P.S: running system config:
>>> - linux x86_64
>>> - python 2.6
>>> - PyQt 4.6.2
>>> - Qt 4.6
>>
>> PyQt caches lookups for Python reimplementations of methods. Monkey
>> patching will only work if you patch a method before it is looked up
for
>> the first time. Your example will work for QWidget if you move the call
>> to
>> show() after you patch it.
>>
>> Phil
>>
> 
> Oh, thanks for the explanation. This raises another question: is there
> any way to flush this PyQt cache from inside my program to force it
> use new monkey-patched version instead of cached?

No.

Phil


More information about the PyQt mailing list