19. Events
In the Qt framework, events are objects derived from the QEvent class that represent occurences, such as user input or system notifications, that require handling. Events are especially relevant for Qt widgets, as they allow widgets to react to changes like mouse movements, keyboard presses, or window resizes. The event system relies on Qt’s event loop, which processes queued events and dispatches them to the appropriate QObject receivers. Developers can customize event handling by overriding virtual event methods in subclasses, providing fine-grained control over application behavior. Common event types include QMouseEvent for pointer interactions, QKeyEvent for keyboard actions, and QPaintEvent for rendering updates1.
There are five ways events can be processed:
- Reimplementing event type-specific event handler methods like
mousePressEvent(). - Reimplementing the
QObject.event()method. - Installing an event filter on the object.
- Installing an event filter on
QCoreApplicationinstance. - Reimplementing the
QCoreApplication.notify()method2.
19.1 Event Handlers
A Qt class main event handler is the event() method. When an event occurs, this method receives a QEvent object representing it. Typically, it does not handle the event itself but instead calls the specific event handler method for that event type. You can override the base class’s event handler completely, in which case you must implement all handling yourself, or handle only certain event types and call the base class method for others.
![]() |
Whenever your application’s main window becomes visible on the screen, add it to the list of visible windows. When it becomes hidden, remove it from the list. Your additional task is to record and suppress key press events when the user presses the letter ‘q’. |
Extend the
keyPressEvent()method. To suppress the ‘q’ key presses, check ifevent.text()equals ‘q’. If it does, record it in a label. SinceQKeyEvent.isAccepted()isTrueby default, this suppresses the ‘q’ key presses. For all other key presses, call the base classkeyPressEvent().Extend the
showEvent()method. Simulate adding the window to a visible windows list by recording the event in the label, then call the base classshowEvent().Extend the
hideEvent()method. When the window is hidden, the label is also hidden, so simulate removing the window from the visible windows list by printing a message. Then call the base classhideEvent()for further processing.
The event() method dispatches events to type-specific event handlers like showEvent() or keyPressEvent(). While you can use it to handle events directly, the documentation recommends using the event type-specific handlers instead. In the example, we intercept key press and show events in event() and print a message for each. Then we call the base class event() for further processing. You can also use event() to suppress events - if you uncomment the two return True statements, events never reach keyPressEvent() and showEvent().
19.2 Object Event Filters
In the previous section we saw how to intercept events by overriding a QObject’s event() method before the events reach the specific event handlers. Sometimes, however, you need to monitor or suppress events destined for other objects. This is achieved by installing an event filter.
![]() |
Your task is to log mouse press events for a group of buttons while completely suppressing clicks on one particular button. |
To use an event filter in your application:
- Create a class that inherits from
QObjectand implement itseventFilter()method. The signature is:
1 def eventFilter(self, watched: QObject, event: QEvent) -> bool
The watched parameter refers to the object receiving the event. In this example, we check for MouseButtonPress events, log them to the console, and return True for button2 to consume the event (preventing further processing, including the clicked() signal). For all other cases, we return the result of the base class implementation.
Instantiate the event filter object (in this case a
MousePressFilterinstance namedevent_filter.Install the event filter on each target widget using
installEventFilter().
If you delete the watched object inside eventFilter(), you need to return True, otherwise the application might crash.
The output is:
1 Filter mouse press for: button1
2 Button clicked: button1
3 Filter mouse press for: button2
4 Filter mouse press for: button3
5 Button clicked: button3
Consuming an event means stopping it from being processed further. The clicked() signal requires Qt to process both a mouse press and a mouse release on the button. By consuming the mouseButtonPress event in the filter, the button never receives the press event, so it can’t recognize a complete click action.
Event filters can be chained, meaning you can install multiple filters on the same object. When event occurs, Qt calls the filters in reverse order of installation.
19.3 Application-Wide Event Filters
In the previous section, we installed an event filter on individual buttons. An event filter installed on the QApplication object, however, can intercept all events for all widgets in the application - including mouse events that would normally be ignored by disabled widgets.
![]() |
You want users to be able to “click” disabled buttons (i.e., trigger their clicked signal) without re-enabling them visually or functionally. |
To implement a global event filter:
Create the event filter class. Override
eventFilter()to detectMouseButtonPressevents If the target widget (thewatchedparameter) is a disabledQPushButton, manually emit itsclicked()signal and consume the event by returningTrue.Instantiate the filter object, passing the
QApplicationinstance as its parent.Install the filter on the
QApplicationinstance usingQApplication.installEventFilter().
Sample console output when clicking each button in order:
1 Filter mouse press for: Main WindowWindow
2 Filter mouse press for: button1
3 Button clicked: button1
4 Filter mouse press for: Main WindowWindow
5 Filter mouse press for: button2
6 Button clicked: button2
7 Filter mouse press for: Main WindowWindow
8 Filter mouse press for: button3
9 Button clicked: button3
Notice that filter receives each mouse press event twice. Qt delivers them first to the top-level window, then to the specific button under the mouse. Since the filter is installed at the application level, it intercepts the event at both stages.
This approach bypasses Qt’s normal disabled-state behavior. Disabled buttons will emit clicked() signals but won’t show visual press feedback. Application-wide filters see every event in your application, so keep the eventFilter() method efficient to avoid perdormance issues.
19.4 Event Propagation
The QCoreApplication.notify() method delivers all events to their receiver objects. Certain event types, such as mouse and key events, propagate up the parent widget chain if the receiver ignores them (i.e., does not accept the event).
![]() |
Your application requires users to create an account. To better understand how they interact with the “Create account” dialog - for usability testing or debugging - you want to log every mouse click and keyboard press, including which widget received the event and how events propagate when not handled. |
To implement a global activity logger:
Create an
EventFilterclass inheriting fromQObject. In itseventFilter()method, detectMouseButtonPressandKeyPressevents and log them to the console.In the main section, after creating the
QApplication, instantiate the filter and install it globally usingQApplication.installEventFilter().Create the main window as a
QWidgetcontaining:
- A
QLineEditfor entering the user name, - A
Qlabelbelow it displaying the generated e-mail address. Make the text selectable so users can copy it. - A checkbox to enable email notifications.
The widgets are nested inside two QGroupBox containers to create a clear parent hierarchy.
Here is a sample output from typical interactions:
1 Log: key pressed in MainWindowWindow
2 Log: key pressed in line_edit
3 Log: mouse pressed in MainWindowWindow
4 Log: mouse pressed in checkbox
5 Log: mouse pressed in MainWindowWindow
6 Log: mouse pressed in label
7 Log: key pressed in MainWindowWindow
8 Log: key pressed in label
9 Log: key pressed in inner_groupbox
10 Log: key pressed in outer_groupbox
11 Log: key pressed in MainWindow
Because the filter is installed at the application level, it sees events at every step of delivery and propagation.Interactive widgets like the line edit and checkbox accept most events they receive, stopping further propagation. The label behaves differently: it accepts mouse presses but ignores most key presses. As a result, key events on the label propagate up through the inner group box, outer group box, and finally the main window.
19.5 Custom Events
Qt allows you to define and post your own event types, extending the event system for application-specific needs. Custom events are processed in the event loop like built-in events and can be handled in the customEvent() handler, event() or via event filters.
To create a custom event:
- Register a unique type with
QEvent.registerEventType(). - Subclass
QEventand add data attributes. - Post instances to receivers using
QApplication.postEvent(receiver, event).
![]() |
Your task is to create a custom Qt event whenever the current CPU usage percent exceeds a threshold. The event should hold the CPU usage percent as the data. |
To create custom Qt events:
Define a custom event class
CpuUsageEventthat inherits fromQEventand carries the used CPU percent value. UseQEvent.registerEventType()to assign a unique type to the class.Use a
QTimerwith an interval of 1000 ms to periodically poll the CPU usage percent withpsutil.cpu_percent.If the CPU percent exceeds the threshold, create and post a new event object to each receiver.
Note that custom events do not automatically propagate up the widget hierarchy like mouse or key events.
