keyPressEvent() with QCalendarWidget
Phil Thompson
phil at riverbankcomputing.com
Mon Nov 7 12:26:25 GMT 2022
On 05/11/2022 23:09, Maurizio Berti wrote:
> [ "crossposted" as John (who I hope doesn't mind) did reply privately,
> but
> I believe that this might be useful to others]
>
> Il giorno sab 5 nov 2022 alle ore 19:48 John F Sturtz <john at sturtz.org>
> ha
> scritto:
>
>> Your method of installing an event filter worked of course. But
>> continuing down the path of idle intellectual curiosity ...
>>
>> Now knowing that the calendar widget has an underlying QTableView, I
>> might
>> have thought I could get the same effect by reassigning the view's
>> keyPressEvent() method. Something like this:
>>
>> class Calendar(QCalendarWidget):
>>
>> def __init__(self, parent=None):
>> super().__init__(parent)
>>
>> self.setDateEditEnabled(False)
>> # self.findChild(QAbstractItemView).installEventFilter(self)
>> self.findChild(QAbstractItemView).keyPressEvent =
>> self.key_press
>>
>> # def eventFilter(self, obj, event):
>> # if (
>> # event.type() == event.KeyPress
>> # and event.key() == Qt.Key_Space
>> # ):
>> # print('space pressed!')
>> # return True
>> # return super().eventFilter(obj, event)
>>
>> def key_press(self, event):
>> key = event.key()
>> mod = int(event.modifiers())
>> handled = False
>>
>> print('key pressed!')
>>
>> if key == Qt.Key_Space:
>> print('space pressed!')
>> handled = True
>>
>> if not handled:
>> super().keyPressEvent(event)
>>
>> I realize that brute-force reassigning the keyPressEvent() method (as
>> opposed to subclassing and re-implementing) is ugly. And I probably
>> wouldn't do it for real. But I have done it on occasion just for
>> purposes
>> of mucking around (including just now, in another test file that I
>> have).
>> And it usually works. I'm a little surprised that it doesn't here.
>>
>
> I cannot provide a complete explanation about the exact reason for
> which it
> doesn't work, as my knowledge of C++ is limited to reading and
> understanding what code does. Also, I don't know how exactly sip works
> with
> overridden C++ functions.
>
> That said, the reason is caused by the fact that the view used in
> QCalendarWidget is actually a private subclass (named QCalendarView)
> which
> on its own overrides keyPressEvent.
> My understanding is that, since that class is not publicly declared,
> you
> cannot override any of its methods, and you can only use its functions
> by
> explicitly calling them (like installing the event filter).
> It's possible that this is related to the "function reference caching"
> (I
> don't know the exact term) that happens when you try to override a
> function
> *after* it's been already called: if you overwrite mousePressEvent
> *after*
> the default implementation has been called, it will not work. This is
> obviously not the case, since you're overwriting it before it can be
> called, but it's possible that it has a similar cause.
>
> If Phil or anybody with enough knowledge of C++/sip would like to
> provide
> more precise explanations about this, I'll be glad to read it.
It's not because of the private sub-class (Python would treat it as the
nearest super class that it knows about) it's because the instance was
created by C++ code rather than by Python code.
For every C++ class that has virtuals SIP defines a sub-class that has
an implementation of each virtual that, when called, sees if there is a
Python method of the same name. If there is it calls the Python method,
if not it calls the original C++ implementation (in the super-class).
When you create an instance of a C++ class from Python you are actually
creating an instance of the SIP-generated sub-class. If C++ has created
the instance then it is of the original class and there is no mechanism
to translate the C++ virtuals to Python methods.
Phil
More information about the PyQt
mailing list