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:

  1. Reimplementing event type-specific event handler methods like mousePressEvent().
  2. Reimplementing the QObject.event() method.
  3. Installing an event filter on the object.
  4. Installing an event filter on QCoreApplication instance.
  5. 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.

An icon of a clipboard-list1

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’.

  1. Extend the keyPressEvent() method. To suppress the ‘q’ key presses, check if event.text() equals ‘q’. If it does, record it in a label. Since QKeyEvent.isAccepted() is True by default, this suppresses the ‘q’ key presses. For all other key presses, call the base class keyPressEvent().

  2. Extend the showEvent() method. Simulate adding the window to a visible windows list by recording the event in the label, then call the base class showEvent().

  3. 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 class hideEvent() 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.

An icon of a clipboard-list1

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:

  1. Create a class that inherits from QObject and implement its eventFilter() 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.

  1. Instantiate the event filter object (in this case a MousePressFilter instance named event_filter.

  2. 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.

An icon of a clipboard-list1

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:

  1. Create the event filter class. Override eventFilter() to detect MouseButtonPress events If the target widget (the watched parameter) is a disabled QPushButton, manually emit its clicked() signal and consume the event by returning True.

  2. Instantiate the filter object, passing the QApplication instance as its parent.

  3. Install the filter on the QApplication instance using QApplication.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).

An icon of a clipboard-list1

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:

  1. Create an EventFilter class inheriting from QObject. In its eventFilter() method, detect MouseButtonPress and KeyPress events and log them to the console.

  2. In the main section, after creating the QApplication, instantiate the filter and install it globally using QApplication.installEventFilter().

  3. Create the main window as a QWidget containing:

  • A QLineEdit for entering the user name,
  • A Qlabel below 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 QEvent and add data attributes.
  • Post instances to receivers using QApplication.postEvent(receiver, event).
An icon of a clipboard-list1

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:

  1. Define a custom event class CpuUsageEvent that inherits from QEvent and carries the used CPU percent value. Use QEvent.registerEventType() to assign a unique type to the class.

  2. Use a QTimer with an interval of 1000 ms to periodically poll the CPU usage percent with psutil.cpu_percent.

  3. 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.


  1. If you don’t implement __init__() in your class at all, the parent class gets initalized automatically.↩︎

  2. https://doc.qt.io/qtforpython-6/↩︎