Master PyQt5 Event Handling and Timers: From Signals to Custom Filters
This article explains PyQt5's event system, covering both high‑level signal‑slot mechanisms and low‑level event handling, lists common event types, demonstrates five event‑processing techniques, and provides step‑by‑step examples of implementing custom event filters and timers using QTimer and timerEvent.
PyQt5 Event Mechanism
PyQt provides two mechanisms for event handling: the high‑level signal‑and‑slot system, which is a wrapper around the low‑level event handling mechanism. The low‑level mechanism deals directly with events.
Common Event Types
Keyboard events: key press and release.
Mouse events: pointer movement, button press and release.
Drag‑and‑drop events.
Wheel events.
Paint events: redraw parts of the screen.
Timer events: timer expiration.
Focus events: keyboard focus changes.
Enter/Leave events: mouse entering or leaving a widget.
Move events: widget position changes.
Resize events: widget size changes.
Show/Hide events: widget visibility.
Window events: activation of a window.
Five Event‑Processing Methods (from weak to strong)
Reimplement specific event functions such as mousePressEvent() , keyPressEvent() , etc.
Reimplement QObject.event() .
Install an event filter on an object.
Install a global event filter on QApplication .
Reimplement QApplication.notify() to intercept all events.
Example: Custom notify and Event Filter
<code>import sys
from PyQt5.Qt import *
# Override QApplication.notify to filter events
class App(QApplication):
def notify(self, receiver, evt):
# Print mouse button press events on QPushButton
if receiver.inherits("QPushButton") and evt.type() == QEvent.MouseButtonPress:
print(receiver, evt)
return super().notify(receiver, evt)
# Subclass QPushButton to filter events
class Btn(QPushButton):
def event(self, evt):
if evt.type() == QEvent.MouseButtonPress:
print(evt)
return super().event(evt)
def mousePressEvent(self, *args, **kwargs):
print("Mouse button pressed...")
return super().mousePressEvent(*args, **kwargs)
app = App(sys.argv)
window = QWidget()
window.setWindowTitle("Event Mechanism")
btn = Btn(window)
btn.setText("Button")
btn.move(100, 100)
def on_click():
print("Button clicked")
btn.pressed.connect(on_click)
window.show()
sys.exit(app.exec_())
</code>PyQt5 Timers
Timers are often needed for periodic tasks such as UI refresh, data updates, or background processing. PyQt offers two ways to use timers:
Implement timerEvent() in an object.
Use the QTimer class.
Using timerEvent()
<code>class MyLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setText("10")
self.move(235, 235)
self.setStyleSheet("font-size: 28px;")
def setSec(self, sec):
self.setText(str(sec))
def startMyTimer(self, ms):
self.timer_id = self.startTimer(ms, timerType=Qt.PreciseTimer)
def timerEvent(self, *args, **kwargs):
current_sec = int(self.text()) - 1
self.setText(str(current_sec))
if current_sec == 0:
print("Countdown stopped")
self.killTimer(self.timer_id)
class MyWidget(QWidget):
def startMyTimer(self, ms):
self.widget_id = self.startTimer(ms, timerType=Qt.PreciseTimer)
def timerEvent(self, *args, **kwargs):
w, h = self.width(), self.height()
self.resize(w + 10, h + 10)
print("Current height", h)
if h == 550:
print("Widget stopped")
self.killTimer(self.widget_id)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWidget()
window.setWindowTitle("QObject Timer Usage")
window.resize(500, 500)
window.startMyTimer(1000)
label = MyLabel(window)
label.setSec(10)
label.startMyTimer(500)
window.show()
sys.exit(app.exec_())
</code>Using QTimer
<code>class Win(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('Timer Usage')
self.resize(300, 300)
self.num = 0
self.setup_ui()
def setup_ui(self):
self.label = QLabel(self)
self.label.move(120, 120)
self.label.setStyleSheet('font-size: 28px;')
self.timer = QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.operate)
self.timer.start()
def operate(self):
self.num += 1
print(self.num)
self.label.setText(str(self.num))
if self.num == 5:
print('Timer stopped')
self.timer.stop()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Win()
win.show()
sys.exit(app.exec_())
</code>Both approaches allow you to execute code at regular intervals, with timerEvent offering low‑level control and QTimer providing a signal‑based, high‑level interface.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.