PyQT: pausing an application for the next event

Srinath Avadhanula srinathava_news at yahoo.com
Mon Oct 13 16:32:50 EDT 2003


[replying to my own email]

It turns out that using generators in python, we can build an equivalent
of the fictional QWaitForNextEvent (which blocks execution till an event
occurs and then returns the event), using generator functions in python.
It is quite cool.

For example, the code

>>> def MySimpleVi(QMultiLineEdit):
>>>     def keyPressEvent(self, event):
>>>         if event.text() == 'd':
>>>             self.deleteLine(event)
>>>
>>>     def deleteLine(self, event):
>>>         count = 0
>>>         movement = None
>>>
>>>         nextevent = QWaitForNextEvent()
>>>         while iscount(nextevent):
>>>             count = 10*count + int(nextevent).text
>>>             nextevent = QWaitForNextEvent()
>>>
>>>         if ismovement(nextevent):
>>>             movement = nextevent.text()
>>>
>>>         range = calculateRange(self.getCursorPosition(), movement, count)
>>>         self.deleteRange(range)

which uses a fictional QWaitForNextEvent() could have been written
without it using generator functions as:

>>>def MySimpleVi(QMultiLineEdit):
>>>    def __init__(self):
>>>        self.handler = None
>>>
>>>    def keyPressEvent(self, event):
>>>        # If we have a handler defined, it means that the handler
>>>        # requires more events to finish.
>>>        if self.handler != None:
>>>            # first store the event in a class-local variable and
>>>            # then call next() method of the handler.
>>>            self.nextevent = event
>>>            if self.handler.next() != None:
>>>                self.handler = None
>>>
>>>        if event.text() == 'd':
>>>            self.handler = self.deleteLine()
>>>            self.handler.next()
>>>
>>>    def deleteLine(self):
>>>        count = 0
>>>        movement = None
>>>
>>>        while iscount(self.nextevent):
>>>            count = 10*count + int(self.nextevent.text())
>>>            # By yielding None, we convey to keyPressEvent that we
>>>            # are not finished yet. We will thus essentially "pause"
>>>            # here till another event occurs and keyPressEvent()
>>>            # calls our next().
>>>            yield None
>>>
>>>        if ismovement(self.nextevent):
>>>            movement = self.nextevent.text()
>>>
>>>        range = calculateRange(self.getCursorPosition(), movement, count)
>>>        self.deleteRange(range)
>>>        # return 1 to signify that we are do not want any more
>>>        # events.
>>>        yield 1


Pretty elegant if I say so myself. The deleteLine() function did not
have to change at all! Ofcourse, without the generator methodology, I
would have had to make things much more complex looking and generally
obfuscated. Hail Python's generators!!! :)

This is ofcourse completely untested yet. It also hinges on the fact
that if the parent function changes self.nextevent, the generator
function sees the new value in the next iteration and not just the
cached value or something of the sort (actually just verified that the
correct thing indeed happens)...

-- 
Srinath





More information about the Python-list mailing list