Proper event-handling in void event(QEvent *)
-
@unzu
What exactly is the expected behavior?
If the custom push button is the ultimate and only consumer of gesture events, they should be accepted andtrue
should be returned to indicate that the event has been consumed.
Theelse
branch becomes obselete, if the method returns within theif
.@Axel-Spoerl
I placed the call to the event-function of the base class into the else branch to process all paint/focus/etc events, while still being able to test the effects of returning true/false in case of the touch/button-press events.I noticed no difference, no matter if I returned true or false in the main branch. That's why I was wondering what results the return value leads to.
Well, I am wondering why I receive the gesture-started event twice in my button.
The first touch press (my finger stays on the button) results in two events being processed by the button event function.
I think its actually the same event being processed twice. The event-state is both times GestureStarted.Greetings.
-
@Axel-Spoerl
I placed the call to the event-function of the base class into the else branch to process all paint/focus/etc events, while still being able to test the effects of returning true/false in case of the touch/button-press events.I noticed no difference, no matter if I returned true or false in the main branch. That's why I was wondering what results the return value leads to.
Well, I am wondering why I receive the gesture-started event twice in my button.
The first touch press (my finger stays on the button) results in two events being processed by the button event function.
I think its actually the same event being processed twice. The event-state is both times GestureStarted.Greetings.
@unzu said in Proper event-handling in void event(QEvent *):
I noticed no difference, no matter if I returned true or false in the main branch. That's why I was wondering what results the return value leads to.
That’s probably because the button has no children to which the event could be delivered if false is returned.
Well, I am wondering why I receive the gesture-started event twice in my button.
The first touch press (my finger stays on the button) results in two events being processed by the button event function.
I think its actually the same event being processed twice. The event-state is both times GestureStarted.Can you post the debug output?
Do both events point to the same memory address? -
Hello everyone,
I've got a few questions about handling events in my own classes.
Right now there are two dummy classes, PushButton and GroupBox which both inherit from their Qt counterparts, QPushButton and QGroupBox.
I have implemented bool event(QEvent*) for testing purposes in both classes:
bool PushButton::event(QEvent *event) { if (auto mouseEvent = dynamic_cast<QMouseEvent *>(event)) { qDebug() << "PushButton" << mouseEvent; //mouseEvent->ignore(); //mouseEvent->accept(); } else return QPushButton::event(event); }
My widget has a custom GroupBox inside of it and a custom PushButton is placed in the GroupBox.
Somewhere in the documentation I've read that the events are by default accepted in most cases:
Pressing the button produces the debug output for the button.
Pressing the groupbox produces the debug output for the groupbox.Uncommenting the mouseEvent ->ignore() propagets the event to the parent.
Pressing the button produces both the debug output for the button and the groupbox.
So far so good. By using accept() and ignore() I can control the event propagation.What about the return value?
The documentation says:bool QObject::event(QEvent *e)
This virtual function receives events to an object and should return true if the event e was recognized and processed.I've tried returning both true and false and could not see any differences.
In addition to that, I have changed the event(QEvent *) function to process QTapGesture in both classes :
if (auto touchEvent = dynamic_cast<QGestureEvent *>(event)) { qDebug() << "GroupBox" << touchEvent; //touchEvent->ignore(); //touchEvent->accept(); } else return QPushButton::event(event);
Touching only the GroupBox gives the expected result: A single QTapGesture(GestureStarted) GroupBox output.
However, touching the PushButton now produces three outputs:
1 - The initial button output.
2 - The output of the GroupBox.
3 - Another button output.Even when accept()-ing the event, I still get two outputs:
1 - The initial button output.
2 - Another button output.Any hints on what is going on there?
Thanks for your time and efforts!
Unzu@unzu said in Proper event-handling in void event(QEvent *):
bool PushButton::event(QEvent *event) { if (auto mouseEvent = dynamic_cast<QMouseEvent *>(event)) { qDebug() << "PushButton" << mouseEvent; //mouseEvent->ignore(); //mouseEvent->accept(); } else return QPushButton::event(event); }
Skipping everything else in the thread, there are 2 significant errors in this code:
-
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
-
Qt traditionally has not required RTTI. dynamic_cast<> may not work. Use QEvent::type() as demonstrated in the example, and static_cast<> if the event object itself is needed.
-
-
@unzu said in Proper event-handling in void event(QEvent *):
bool PushButton::event(QEvent *event) { if (auto mouseEvent = dynamic_cast<QMouseEvent *>(event)) { qDebug() << "PushButton" << mouseEvent; //mouseEvent->ignore(); //mouseEvent->accept(); } else return QPushButton::event(event); }
Skipping everything else in the thread, there are 2 significant errors in this code:
-
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
-
Qt traditionally has not required RTTI. dynamic_cast<> may not work. Use QEvent::type() as demonstrated in the example, and static_cast<> if the event object itself is needed.
@jeremy_k said in Proper event-handling in void event(QEvent *):
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
Indeed it's "undefined". I'm surprised it compiles without error or at least warning!
-
-
@jeremy_k said in Proper event-handling in void event(QEvent *):
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
Indeed it's "undefined". I'm surprised it compiles without error or at least warning!
@JonB said in Proper event-handling in void event(QEvent *):
@jeremy_k said in Proper event-handling in void event(QEvent *):
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
Indeed it's "undefined". I'm surprised it compiles without error or at least warning!
The diagnostic might be optional. gcc 12.1 reports:
warning: control reaches end of non-void function [-Wreturn-type]
-
@JonB said in Proper event-handling in void event(QEvent *):
@jeremy_k said in Proper event-handling in void event(QEvent *):
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
Indeed it's "undefined". I'm surprised it compiles without error or at least warning!
The diagnostic might be optional. gcc 12.1 reports:
warning: control reaches end of non-void function [-Wreturn-type]
-
Probably an inheritance from the C legacy.
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Section 6.9.1.12:If the } that terminates a function is reached, and the value of the function call is used by
the caller, the behavior is undefined -
@unzu said in Proper event-handling in void event(QEvent *):
bool PushButton::event(QEvent *event) { if (auto mouseEvent = dynamic_cast<QMouseEvent *>(event)) { qDebug() << "PushButton" << mouseEvent; //mouseEvent->ignore(); //mouseEvent->accept(); } else return QPushButton::event(event); }
Skipping everything else in the thread, there are 2 significant errors in this code:
-
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
-
Qt traditionally has not required RTTI. dynamic_cast<> may not work. Use QEvent::type() as demonstrated in the example, and static_cast<> if the event object itself is needed.
@jeremy_k said in Proper event-handling in void event(QEvent *):
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
Hey, thanks for your hints.
I've tried to explain it already a few posts above: In my actual code there was a return statement in both branches of the if/else block.
I alternately tested the effects of returning true/false and accepting/ignoring and forgot to add it to my small code snipped. I should've edited it right away after @Axel-Spoerl mentioned it. I will leave it for now to preserve the context.
Regarding your other point, I think the dynamic_cast actually screwed it up:
"TopButton" is placed ontop/inside of "BottomButton" (added to the layout of BottomButton). Both are PushButtons. This code produces the following result:
bool PushButton::event(QEvent *event) { if(auto gestureEvent = dynamic_cast<QGestureEvent*>(event)) { if(auto tapGesture = gestureEvent->gesture(Qt::TapGesture)) { qDebug() << text() << tapGesture; event->accept(); return true; } else { qDebug() << text() << "Event was no Tap-Gesture." << gestureEvent; event->accept(); return true; } } return QPushButton::event(event); }
- "TopButton" QTapGesture(state=GestureStarted,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(GestureOverride, 0x2431ef25f0)
- "TopButton" QTapGesture(state=GestureStarted,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(Gesture, 0x2431ef25f0)
- "TopButton" QTapGesture(state=GestureUpdated,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(Gesture, 0x2431ef25f0)
- "TopButton" QTapGesture(state=GestureFinished,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(Gesture, 0x2431ef25f0)
Meanwhile, the edited version of the code shown below leads to:
bool PushButton::event(QEvent *event) { if(event->type() == QEvent::Type::Gesture) { auto gestureEvent = dynamic_cast<QGestureEvent*>(event); if(auto tapGesture = gestureEvent->gesture(Qt::TapGesture)) { qDebug() << text() << tapGesture << event; event->accept(); return true; } else { qDebug() << text() << "Event was no Tap-Gesture." << gestureEvent; event->accept(); return true; } } return QPushButton::event(event); }
- "TopButton" QTapGesture(state=GestureStarted,hotSpot=753.5,222,position=67.5,9) QGestureEvent(Gesture, 0xb261be2430)
- "TopButton" QTapGesture(state=GestureUpdated,hotSpot=753.5,222,position=67.5,9) QGestureEvent(Gesture, 0xb261be2430)
- "TopButton" QTapGesture(state=GestureFinished,hotSpot=753.5,222,position=67.5,9) QGestureEvent(Gesture, 0xb261be2430)
So I guess its working properly? :)
Another question related to this topic:
I receive the event in state GestureStarted and i accept() it.
Moving my finger produces the GestureUpdate-events until I leave the button or withdraw my finger.
Am I supposed to accept() those updates aswell?Thanks for all the answers!
Edit: Do you know why the coloring of my code extracts looks so messy?
-
-
@jeremy_k said in Proper event-handling in void event(QEvent *):
The if branch contains no return statement, and there is no return statement after the if/else block. I believe this results in undefined behavior, but may be mistaken.
Hey, thanks for your hints.
I've tried to explain it already a few posts above: In my actual code there was a return statement in both branches of the if/else block.
I alternately tested the effects of returning true/false and accepting/ignoring and forgot to add it to my small code snipped. I should've edited it right away after @Axel-Spoerl mentioned it. I will leave it for now to preserve the context.
Regarding your other point, I think the dynamic_cast actually screwed it up:
"TopButton" is placed ontop/inside of "BottomButton" (added to the layout of BottomButton). Both are PushButtons. This code produces the following result:
bool PushButton::event(QEvent *event) { if(auto gestureEvent = dynamic_cast<QGestureEvent*>(event)) { if(auto tapGesture = gestureEvent->gesture(Qt::TapGesture)) { qDebug() << text() << tapGesture; event->accept(); return true; } else { qDebug() << text() << "Event was no Tap-Gesture." << gestureEvent; event->accept(); return true; } } return QPushButton::event(event); }
- "TopButton" QTapGesture(state=GestureStarted,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(GestureOverride, 0x2431ef25f0)
- "TopButton" QTapGesture(state=GestureStarted,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(Gesture, 0x2431ef25f0)
- "TopButton" QTapGesture(state=GestureUpdated,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(Gesture, 0x2431ef25f0)
- "TopButton" QTapGesture(state=GestureFinished,hotSpot=703.5,224.5,position=17.5,11.5) QGestureEvent(Gesture, 0x2431ef25f0)
Meanwhile, the edited version of the code shown below leads to:
bool PushButton::event(QEvent *event) { if(event->type() == QEvent::Type::Gesture) { auto gestureEvent = dynamic_cast<QGestureEvent*>(event); if(auto tapGesture = gestureEvent->gesture(Qt::TapGesture)) { qDebug() << text() << tapGesture << event; event->accept(); return true; } else { qDebug() << text() << "Event was no Tap-Gesture." << gestureEvent; event->accept(); return true; } } return QPushButton::event(event); }
- "TopButton" QTapGesture(state=GestureStarted,hotSpot=753.5,222,position=67.5,9) QGestureEvent(Gesture, 0xb261be2430)
- "TopButton" QTapGesture(state=GestureUpdated,hotSpot=753.5,222,position=67.5,9) QGestureEvent(Gesture, 0xb261be2430)
- "TopButton" QTapGesture(state=GestureFinished,hotSpot=753.5,222,position=67.5,9) QGestureEvent(Gesture, 0xb261be2430)
So I guess its working properly? :)
Another question related to this topic:
I receive the event in state GestureStarted and i accept() it.
Moving my finger produces the GestureUpdate-events until I leave the button or withdraw my finger.
Am I supposed to accept() those updates aswell?Thanks for all the answers!
Edit: Do you know why the coloring of my code extracts looks so messy?
@unzu said in Proper event-handling in void event(QEvent *):
Moving my finger produces the GestureUpdate-events until I leave the button or withdraw my finger.
Am I supposed to accept() those updates aswell?That depends on the use case. If another
QObject
should do something reasonable with these events, it's better to ignore them. If the custom button is supposed to absorb the noise and make sure, nothing gets distracted - it's better to accept and returntrue
(even if nothing is actually done).Edit: Do you know why the coloring of my code extracts looks so messy?
Have seen that before. No clue where that comes from.
-
@unzu said in Proper event-handling in void event(QEvent *):
Moving my finger produces the GestureUpdate-events until I leave the button or withdraw my finger.
Am I supposed to accept() those updates aswell?That depends on the use case. If another
QObject
should do something reasonable with these events, it's better to ignore them. If the custom button is supposed to absorb the noise and make sure, nothing gets distracted - it's better to accept and returntrue
(even if nothing is actually done).Edit: Do you know why the coloring of my code extracts looks so messy?
Have seen that before. No clue where that comes from.
@Axel-Spoerl said in Proper event-handling in void event(QEvent *):
That depends on the use case. If another QObjectshould do something reasonable with these events, it's better to ignore them. If the custom button is supposed to absorb the noise and make sure, nothing gets distracted - it's better to accept and return true(even if nothing is actually done).
Okay, will do that.
So far my touch-buttons are working mostly fine.However there is still one annyoing thing:
If I place multiple of those buttons together in a groupbox, frame, etc., I can trigger multiple tap gestures at the same sime.
-
Pressing Button A
Button A "Gesture started" -
Pressing Button B
Button B "Gesture started" -
Withdrawing one finger from Button A/B
Button A/B "Gesture finished" -
Withdrawing second finger from other Button B/A
Button B/A "Gesture finished"
This behaviour is fine for me: It is actually multi-touch support and does not hurt me.
However, if I accidentally touch the underlying QGroupBox, the event gets canceled:-
Pressing Button A
Button A "Gesture started" -
Touching the GroupBox with a second finger
Button A "Gesture canceled" -
Withdrawing one finger of Button A or the GroupBox
Nothing happens. -
Withdrawing the second finger
Nothing happens.
Is there a way to setup these events so that the behaviour is uniform:
- Touching something other than the currently pressed Button always causes "Gesture canceled" in the Button (basically only single-touch support)
- Touching something other than the currently pressed Button never causes "gesture canceled" (basically multi-touch support).
Thanks for your support!
-