QLineEdit::returnPressed when something else has a Key_Return shortcut
-
Either subclass and override
event()
to handleQEvent::ShortcutOverride
or install a filter and check for the same. In either caseaccept()
the event and return true when it's the return key. This will override the shortcut and pass the event through to the widget to handle as usual.BTW, how do these shortcuts and keys work?
With no shortcuts involved it's just a bubble up thing - the click goes to whatever was under the cursor and accepts clicks. If you put a "transparent for clicks" flag on a widget the click goes to whatever is under it and so on all the way to the bottom. With buttons it's similar - focused widget gets it first and if it doesn't accept keyboard the event bubbles up through parents until something handles it.
How shortcuts work depends on the scope. Assuming you have the default window scope when a button is pressed the widget that has focus gets ShortcutOverride event first. If it rejects it (the default) the shortcut swallows the button. If it accepts it the shortcut is overriden and the press is handled as usual i.e. the widget gets a key press event.
-
@Chris-Kawa
Great stuff. I have plenty to try from all three of you, thanks :) -
Morning folks :)
I took @Chris-Kawa's suggestion of
QEvent::ShortcutOverride
, which I did not know about and seems to be exactly what I want: just don't let a shortcut onKey_Return
activate while focus is in myQLineEdit
, then leave return to be acted on by the line edit just as however it does it now. I did it withinstallEventFilter()
. And that worked fine.Then, I am a bit of a "purist" in my coding :) I thought about it and decided to subclass
QLineEdit
and do the same but in itsevent()
. You could argue both ways. But theinstallEventFilter()
requires (a) the parent main window to provide aneventFilter()
method for the line edit and (b) the parent to callinstallEventFilter()
on behalf of the line edit. Say I am a junior programmer, tasked with writing the line edit code, but not to bother the senior programmers who look after the main window :) I decided, for right or for wrong, to make it so the line edit behaviour is "self-contained": no matter where it is hosted it does not want to allow a Return shortcut to take that away from itself.So final code:
/*virtual*/ bool SpecialLineEdit::event(QEvent *e) /*override*/ { if (e->type() == QEvent::ShortcutOverride) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e); if (keyEvent->key() == Qt::Key_Return) { // next line added for correct solation as per @Chris-Kawa's comment below e->accept(); return true; } } return QLineEdit::event(e); }
Everyone happy with this? :)
Thanks to all who participated.
-
-
@JonB You're missing a call to
e->accept()
before returning true.Also, as a side note, since full keyboard users often use them interchangeably and QLineEdit also supports it, you should probably treat
Key_Enter
the same way if you want to be safe. And yes, the QLineEdit's signal is calledreturnPressed
, but it is emitted for both Return and Enter. -
@Chris-Kawa said in QLineEdit::returnPressed when something else has a Key_Return shortcut:
@JonB You're missing a call to e->accept() before returning true.
Funny, because I was going to ask about just this but didn't get around to it. I wondered if caller goes
if (event(e) || e->isAccepted)
but I guess they are different. It works, but doubtless because of default value or something. What is the difference/relationship between return result of
event()
and setting/clearingaccepted
, please?Will do for
Key_Enter
. Is that the key on my numeric pad which I have never used once in my life? -
What is the difference/relationship between return result of event() and setting/clearing accepted, please?
Return value says whether your handler handled the event i.e. if you return false the filter will go to the next guy in the chain. If you return true it stops with you.
accept
sets a property of the event itself - so anyone getting the pointer can check whether it was accepted.While usually they're set symmetrically you could also reject the event and return true, meaning the event should be ignored and no one else should look at it or you could call accept and return false, meaning you consider the event handled by you, but if anyone else in the chain wants a stab at it they can.
Will do for Key_Enter. Is that the key on my numeric pad which I have never used once in my life?
Yup, that's the one :)
-
@Chris-Kawa
Thanks, interesting.Take my case. Clearly the vital thing is the return result (I don't want anyone else/the shortcut handler to deal with it), which I have right. Let's say I fail to
accept()
. What difference could that make? Nobody else could look at it? Does that matter?If
Key_Enter
is the unknown key on the right, I certainly don't want my line edit contaminated by bothering to handle it. Undefined behaviour is fine. I'm actually happy to leave that as a shortcut if it's wanted. -
Let's say I fail to accept(). What difference could that make? Nobody else could look at it? Does that matter?
If you don't accept and return true it basically means "I've handled this event by deciding it doesn't matter". Keep in mind that this refers to the ShortcutOverride event, not the key press, so in other words it's "I've handled the event by ensuring nobody is overriding the shortcut. Let it eat the key".
That's how it works for this particular case. Not all events are made equal though. Some of them are more of a notification than a question, like when the OS informs you a color scheme has changed. You can't really meaningfully reject those events, as they are just informing you that something already happened, so nobody is looking at whether you accept those or not.
The return value is part of the event propagation mechanism to figure out when to stop propagating. The accepted/rejected bool is sort of a payload of the event that tells the sender at the end of propagation whether you did something with the event or not. That information is not always interesting to the sender, so some check it and some don't.If Key_Enter is the unknown key on the right, I certainly don't want my line edit contaminated by bothering to handle it
It already does handle it. There are two keys that do the same thing on the QLineEdit, but you only defended against shortcut shadowing one of them. I just suggested to defend them both for consistency, but it's of course up to you which user habits you support.
Personally I use Enter all the time. It's just closer than Return when I have my hand on a mouse to the right, so I can just reach out with a thumb :)
-
@Chris-Kawa
Thanks. Sorry to press, but I'm interested and still don't quite get the effect. Obviously I understand here I will accept as well as return true. But can you give an example (not code just explanation) of any event override where returning true but failing to accept causes some different behaviour upstream (or do I mean downstream?) behaviour from if it had also accepted it? A tangible example where behaviour would differ.I have the mouse maybe 10 inches from the edge of the keyboard. My thumb is not that long! I have never used the numeric keypad or the Enter key ever on any keyboard. Frankly I suspect they are devil's spawn, there to tempt the unwary into unnecessary wickedness and gluttony.
-
-
can you give an example (not code just explanation) of any event override where returning true but failing to accept causes some different behaviour
A very common example is the close event. If you
accept()
it the window will close. If youignore()
it the window will stay open.Frankly I suspect they are devil's spawn, there to tempt the unwary into unnecessary wickedness and gluttony.
All true. Those who had congress with the beast tend to develop elongated fingers turning into claws further down the line, letting them reach the notoriously elusive and distant Enter key with more ease.
-
@Chris-Kawa
I'm not going to lie, I still don't fully understand the behaviour/consequences forevent->accept()
or not! However, I discovered that the code I had without it did not always work correctly (sometimes it did, sometimes not when it hit myreturn true
but still it treated it as a shortcut). I put ine->accept()
and now it works consistently, and so I have corrected my solution code to include it. -
@JonB Maybe this example will help. Say you have a hierarchy of widgets like this:
Window -> TabWidget -> Groupbox -> TextEditWhen you send some event to the TextEdit the sequence in pseudo code is like this:
QWidget* widget = TextEdit; QEvent* event = ... while(widget && !widget->event(event)) { widget = widget->parentWidget(); } bool result = event->isAccepted(); doSomethingWithResult(result);
i.e. it goes up the parent tree until one of the widgets returns true and then it checks whether the event was accepted or not and does something with it.
If you return true but don't either accept or ignore the event it will be left in whatever state the previous handler on the stack left it with. If you're the only one or none of the handlers touched it it's gonna be whatever the event sender initialized it with and that differs depending on event - some are accepted by default and some are ignored by default.
-
@Chris-Kawa
6 lines of code are worth a thousand words ;) Perfectly clear now! -