【第五節】PyQt5事件和訊號
文章目錄 [ 顯示 ]
在這一部分的pyqt5教程中,我們將探討PyQt5中的事件Event
事件 Event
所有的GUI程式都是事件驅動的。事件主要由使用者觸發,但也可能有其他觸發方式:例如網路連線、window manager或定時器。當我們呼叫QApplication的exec_()方法時會使程式進入主迴圈。主迴圈會獲取並分發事件。
在事件模型中,有三個參與者:
- 事件源
- 事件物件
- 事件接收者
事件源是狀態發生變化的物件。它會生成事件。事件(物件)封裝了事件源中狀態的變動。事件接收者是要通知的物件。事件源物件將事件處理的工作交給事件接收者。
PyQt5有一個獨特的signal&slot(訊號槽)機制來處理事件。訊號槽用於物件間的通訊。signal在某一特定事件發生時被觸發,slot可以是任何callable物件
訊號槽 Signals & slots
這是一個使用訊號槽的PyQt5例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ Py40 PyQt5 tutorial In this example, we connect a signal of a QSlider to a slot of a QLCDNumber. author: Jan Bodnar website: py40.com last edited: January 2015 """ import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QVBoxLayout, QApplication) class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): lcd = QLCDNumber(self) sld = QSlider(Qt.Horizontal, self) vbox = QVBoxLayout() vbox.addWidget(lcd) vbox.addWidget(sld) self.setLayout(vbox) sld.valueChanged.connect(lcd.display) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Signal & slot') self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) |
這個例子中展示了一個QtGui.QLCDNumber和QtGui.QSlider。lcd的值會隨著滑塊的拖動而改變。
1 |
sld.valueChanged.connect(lcd.display) |
在這裡我們將滾動條的valueChanged訊號連線到lcd的display插槽。
sender是發出訊號的物件。receiver是接收訊號的物件。slot(插槽)是對訊號做出反應的方法。
重新實現事件處理器
在PyQt5中常通過重新實現事件處理器來處理事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ pyu40 PyQt5 tutorial In this example, we reimplement an event handler. author: Jan Bodnar website: py40.com last edited: January 2015 """ import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QWidget, QApplication class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Event handler') self.show() def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) |
在示例中我們重新實現了keyPressEvent()事件處理器。
1 2 3 |
def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close() |
我們按下Escape鍵會使程式退出。
事件傳送者
有時需要知道訊號是由哪個控制元件發出的。對此PyQt5提供了sender()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# -*- coding: utf-8 -*- """ PyQt5 tutorial In this example, we determine the event sender object. author: py40.com last edited: 2017年3月 """ import sys from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication class Example(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): btn1 = QPushButton("Button 1", self) btn1.move(30, 50) btn2 = QPushButton("Button 2", self) btn2.move(150, 50) btn1.clicked.connect(self.buttonClicked) btn2.clicked.connect(self.buttonClicked) self.statusBar() self.setGeometry(300, 300, 290, 150) self.setWindowTitle('Event sender') self.show() def buttonClicked(self): sender = self.sender() self.statusBar().showMessage(sender.text() + ' was pressed') if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) |
我們建立了兩個按鈕。在buttonClicked()方法中通過呼叫sender()方法來判斷當前按下的是哪個按鈕。
1 2 |
btn1.clicked.connect(self.buttonClicked) btn2.clicked.connect(self.buttonClicked) |
兩個按鈕連線到了同一個插槽。
1 2 3 4 |
def buttonClicked(self): sender = self.sender() self.statusBar().showMessage(sender.text() + ' was pressed') |
我們通過呼叫sender()方法來判斷訊號源, 並將其名稱顯示在窗體的狀態列中。
發出訊號
通過QObject建立的物件可以發出訊號。下面的示例演示瞭如何發出自定義訊號
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# -*- coding: utf-8 -*- """ PyQt5 tutorial In this example, we determine the event sender object. author: py40.com last edited: 2017年3月 """ import sys from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtWidgets import QMainWindow, QApplication class Communicate(QObject): closeApp = pyqtSignal() class Example(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.c = Communicate() self.c.closeApp.connect(self.close) self.setGeometry(300, 300, 290, 150) self.setWindowTitle('Emit signal') self.show() def mousePressEvent(self, event): self.c.closeApp.emit() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) |
我們建立了一個名為closeApp的訊號。這個訊號會在按下滑鼠時觸發,它連線著QMainWindow的close()插槽。
1 2 |
class Communicate(QObject): closeApp = pyqtSignal() |
訊號closeApp是Communicate的類屬性,它由pyqtSignal()建立。
1 2 |
self.c = Communicate() self.c.closeApp.connect(self.close) |
自定義closeApp訊號連線到QMainWindow的close槽
1 2 3 |
def mousePressEvent(self, event): self.c.closeApp.emit() |
當在窗體上點選滑鼠時會觸發closeApp訊號,使程式退出。