PyQt5教程(四)——事件與信號

原文:http://zetcode.com/gui/pyqt5/eventssignals/python

在這部分教程中咱們將探討在程序內部發生的事件與信號。web

事件

全部的GUI程序都是事件驅動的。事件主要由用戶觸發,但也可能有其餘觸發方式:例如網絡鏈接、window manager或定時器。當咱們調用QApplication的exec_()方法時會使程序進入主循環。主循環會獲取並分發事件。網絡

在事件模型中有三個參與者:app

  • 事件源
  • 事件(對象)
  • 事件接收者

事件源是狀態發生變化的對象。它會生成事件。事件(對象)封裝了事件源中狀態的變更。事件接收者是要通知的對象。事件源對象將事件處理的工做交給事件接收者。ide

PyQt5有一個獨特的signal&slot(信號槽)機制來處理事件。信號槽用於對象間的通訊。signal在某一特定事件發生時被觸發,slot能夠是任何callable對象。當signal觸發時會調用與之相連的slot。ui

Signals & slots

這是一個演示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

Signal & slot

從新實現事件處理器

在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()方法來判斷信號源, 並將其名稱顯示在窗體的狀態欄中。

Event 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的信號。這個信號會在按下鼠標時觸發,它鏈接着QMainWindowclose()插槽。

class Communicate(QObject):
    
    closeApp = pyqtSignal()

信號closeAppCommunicate的類屬性,它由pyqtSignal()建立。

self.c = Communicate()
self.c.closeApp.connect(self.close)

自定義信號closeApp鏈接着QMainWindow的close()插槽。

def mousePressEvent(self, event):
    
    self.c.closeApp.emit()

當在窗體上點擊鼠標時會觸發closeApp信號,使程序退出。

咱們在這部分教程中介紹了PyQt5的信號槽機制。

相關文章
相關標籤/搜索