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

z zoomer.gm at gmail.com
Sat Jan 2 12:38:00 GMT 2010


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?



More information about the PyQt mailing list