Chapter 14. Events

Ever faced a situation where the UI “lives its own life”: a button gets clicked but the click coordinates are lost; the window flickers during resize; drag-and-drop behaves unpredictably — and it’s unclear where exactly the logic “breaks”?

This chapter will reveal what actually happens inside Qt when “something happens”. You’ll discover why signals and slots don’t replace events, and learn the secret of how professional developers gain precise control over input (mouse/keyboard/touch) without code chaos and without sacrificing performance.

We’ll cover accept()/ignore() and the chain of propagation up the hierarchy, QEvent::type() and the central event() handler, along with practical cases involving QMouseEvent, QKeyEvent, and QPaintEvent — including the “compression” of repaint events that can save you unnecessary paintEvent() calls and make your interface noticeably more responsive.

Don’t put this off: if you’re writing custom widgets or want to stop “guessing” UI behavior, skipping this chapter is risky.

This chapter includes ready-to-use code examples.

Chapter Self-Check

Why are events considered a lower-level mechanism compared to signals and slots?Answer
Correct answer: Events provide detailed information about user actions (mouse coordinates, key codes), whereas signals are high-level notifications without details. Events are handled by one method, while signals can be connected to multiple slots.
What consequences will calling the ignore() method in an event handler cause, and when might this be useful?Answer
Correct answer: The ignore() method passes the event to the parent object for further processing. This is useful when a widget cannot fully handle an event and wants to delegate it to its parent.
Why is mouseMoveEvent() only called by default when a mouse button is pressed?Answer
Correct answer: This is a performance optimization — it prevents creating unnecessary events during simple pointer movement. To track all movements, you need to call setMouseTracking(true).
What will happen if you disable double buffering by calling setAttribute(Qt::WA_PaintOnScreen)?Answer
Correct answer: Graphics will disappear when the window is resized or covered by other windows, because without buffering you need to constantly redraw content in paintEvent().
Why does Qt “compress” a series of QPaintEvent events into one event?Answer
Correct answer: For performance optimization — multiple paint events are combined into one with a common region, resulting in a single paintEvent() call instead of multiple ones.
Why are event handling methods defined as virtual protected in Qt?Answer
Correct answer: Virtual allows methods to be overridden in derived classes, and protected restricts their invocation to within the class and descendants only, which matches Qt’s event system architecture.
In what cases should you override the event() method instead of specialized handlers?Answer
Correct answer: Only for handling event types that don’t have specialized methods, or when you need to intercept an event before it’s dispatched. In all other cases, it’s better to use specialized methods.
Why doesn’t the Tab key generate keyPressEvent() by default?Answer
Correct answer: The Tab key is processed by the event() method for focus management — passing focus to the next widget, which is system UI behavior.
How do you properly handle mouse wheel scrolling to support different devices (mouse and trackpad)?Answer
Correct answer: You need to check both methods: angleDelta() for mouse wheels and pixelDelta() for trackpads, using whichever returns a non-empty value.
What will happen if you don’t call processEvents() in an intensive loop?Answer
Correct answer: The GUI will “freeze” — it will stop responding to user actions and won’t repaint, because the event queue isn’t being processed during loop execution.
Why is mousePressEvent() called twice during a double-click?Answer
Correct answer: A double-click is processed as two separate presses plus a mouseDoubleClickEvent(), so the application can respond to both single and double clicks.
Why do you need to set the Qt::WA_AcceptsTouchEvents attribute to handle multitouch?Answer
Correct answer: By default, widgets ignore multitouch events and convert them to mouse events. The attribute enables receiving real QTouchEvent multitouch events.
How do you determine which of 10 touch points belongs to a specific finger in a multitouch interface?Answer
Correct answer: Using the TouchPoint::id() method, which returns a unique touch point identifier that persists throughout the gesture from press to release.
Why do the modifiersInfo() and buttonsInfo() methods use bitwise AND (&) to check status?Answer
Correct answer: Button and modifier states are stored as a bitmask, where each bit represents a separate button. Bitwise AND checks whether a specific bit is set in the combination.
What value should the event() method return to prevent further propagation of the event to ancestors?Answer
Correct answer: The method should return true, meaning the event was fully handled. Returning false will pass the event to the parent widget for further processing.

Practical Exercises

Easy Level

Key Information Widget
Create a widget that displays information about the pressed key: its code, Unicode character (if any), and modifier key status (Shift, Ctrl, Alt). When a key is pressed, the information should update in a QLabel. Implement handling for both key press (keyPressEvent) and key release (keyReleaseEvent) with different background colors.
Hints: Inherit from QLabel. Use the key(), text(), and modifiers() methods of QKeyEvent. To change background color, use setStyleSheet(). Compare the key() value with Qt::Key_* constants.
Medium Level

Mouse Path Drawing
Develop a drawing widget that remembers the mouse path when the left button is pressed and displays it as a line. When the right button is pressed, the line color should change. Implement mouse movement tracking even without pressed buttons, showing the current cursor position with a semi-transparent circle. Add the ability to clear the canvas with the Escape key.
Hints: Use QVector<QPoint> to store path points. Call setMouseTracking(true) to track all movements. In paintEvent(), draw lines through saved points. Handle mousePressEvent, mouseMoveEvent, and keyPressEvent events.
Hard Level

Multitouch Canvas with Gestures
Create an advanced drawing canvas with multitouch gesture support: drawing with multiple fingers simultaneously (each finger draws a line of a different color), pinch-to-zoom gesture with two fingers to change brush thickness, two-finger rotation gesture to rotate the canvas. Implement indication of active touch points and display of current brush thickness. Add a button to reset zoom and rotation.
Hints: Activate setAttribute(Qt::WA_AcceptsTouchEvents). In event(), handle QEvent::TouchBegin/Update/End. Use QMap<int, QVector<QPointF>> to store trajectories of each finger by id(). For scaling, calculate the distance between two points. For rotation, use QLineF::angleTo(). Apply QTransform for drawing transformations.

💬 Join the Discussion!

Figured out keyboard and mouse events? Have questions about the difference between events and signals?

Ran into issues handling multitouch gestures or not sure when to use event() versus specialized handlers?

Share your experience implementing custom events, ask questions about performance, or help other readers master Qt’s event model!

Leave a Reply

Your email address will not be published. Required fields are marked *