原文:http://zetcode.com/gui/pyqt5/eventssignals/python
在這部分教程中咱們將探討在程序內部發生的事件與信號。web
全部的GUI程序都是事件驅動的。事件主要由用戶觸發,但也可能有其餘觸發方式:例如網絡鏈接、window manager或定時器。當咱們調用QApplication的exec_()
方法時會使程序進入主循環。主循環會獲取並分發事件。網絡
在事件模型中有三個參與者:app
事件源是狀態發生變化的對象。它會生成事件。事件(對象)封裝了事件源中狀態的變更。事件接收者是要通知的對象。事件源對象將事件處理的工做交給事件接收者。ide
PyQt5有一個獨特的signal&slot(信號槽)機制來處理事件。信號槽用於對象間的通訊。signal在某一特定事件發生時被觸發,slot能夠是任何callable對象。當signal觸發時會調用與之相連的slot。ui
這是一個演示PyQt5信號槽的簡單示例。this
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ ZetCode PyQt5 tutorial In this example, we connect a signal of a QSlider to a slot of a QLCDNumber. author: Jan Bodnar website: zetcode.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
的值會隨着滑塊的拖動而改變。code
sld.valueChanged.connect(lcd.display)
在這裏咱們將滑動條的valueChanged信號鏈接到lcd的display插槽。對象
sender
是發出信號的對象。receiver
是接收信號的對象。slot
(插槽)是對信號作出反應的方法。blog
在PyQt5中常經過從新實現事件處理器來處理事件。
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ ZetCode PyQt5 tutorial In this example, we reimplement an event handler. author: Jan Bodnar website: zetcode.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()
事件處理器。
def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close()
咱們按下Escape鍵會使程序退出。
有時須要知道信號是由哪一個控件發起的。對此PyQt5提供了sender()
方法。
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ ZetCode PyQt5 tutorial In this example, we determine the event sender object. author: Jan Bodnar website: zetcode.com last edited: January 2015 """ 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()
方法來判斷當前按下的是哪一個按鈕。
btn1.clicked.connect(self.buttonClicked) btn2.clicked.connect(self.buttonClicked)
兩個按鈕鏈接到了同一個插槽。
def buttonClicked(self): sender = self.sender() self.statusBar().showMessage(sender.text() + ' was pressed')
咱們經過調用sender()
方法來判斷信號源, 並將其名稱顯示在窗體的狀態欄中。
經過QObject
建立的對象能夠發出信號。下面的示例演示瞭如何發出自定義信號。
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ ZetCode PyQt5 tutorial In this example, we show how to emit a signal. author: Jan Bodnar website: zetcode.com last edited: January 2015 """ 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()
插槽。
class Communicate(QObject): closeApp = pyqtSignal()
信號closeApp
是Communicate
的類屬性,它由pyqtSignal()
建立。
self.c = Communicate() self.c.closeApp.connect(self.close)
自定義信號closeApp
鏈接着QMainWindow的close()
插槽。
def mousePressEvent(self, event): self.c.closeApp.emit()
當在窗體上點擊鼠標時會觸發closeApp信號,使程序退出。
咱們在這部分教程中介紹了PyQt5的信號槽機制。