PyQt5信號(hào)與槽機(jī)制案例詳解
信號(hào)和槽機(jī)制是 QT 的核心機(jī)制,要精通 QT 編程就必須對(duì)信號(hào)和槽有所了解。信號(hào)和槽是一種高級(jí)接口,應(yīng)用于對(duì)象之間的通信,它是 QT 的核心特性,也是 QT 區(qū)別于其它工具包的重要地方。
信號(hào)和槽是用來在對(duì)象間傳遞數(shù)據(jù)的方法:當(dāng)一個(gè)特定事件發(fā)生的時(shí)候,信號(hào)會(huì)被發(fā)射出來,槽調(diào)用是用來響應(yīng)相應(yīng)的信號(hào)的。Qt中對(duì)象已經(jīng)包含了許多預(yù)定義的信號(hào)(基本組件都有各自特有的預(yù)定義的信號(hào)),根據(jù)使用的場(chǎng)景也可以添加新的信號(hào)。同樣Qt的對(duì)象中已經(jīng)包含了許多預(yù)定義的槽函數(shù),但也可以根據(jù)使用的場(chǎng)景添加新的槽函數(shù)。
一、概念簡介
所有繼承qwidget的控件都支持信號(hào)與槽機(jī)制。
信號(hào):當(dāng)一個(gè)信號(hào)發(fā)生改變時(shí),向外界發(fā)出的信息。
當(dāng)一個(gè)信號(hào)被發(fā)射的時(shí)候,與其關(guān)聯(lián)的槽函數(shù)被立刻執(zhí)行。其中該對(duì)象只負(fù)責(zé)發(fā)送信號(hào),發(fā)射該信號(hào)的對(duì)象并不知道是那個(gè)對(duì)象在接收這個(gè)信號(hào)。這樣保證了對(duì)象與對(duì)象之間的低耦合。
如果存在信號(hào)和多個(gè)槽函數(shù)相關(guān)聯(lián)的時(shí)候,當(dāng)信號(hào)被發(fā)射時(shí),這些槽的執(zhí)行順序?qū)?huì)是隨機(jī)的、不確定的。
槽:一個(gè)執(zhí)行某些操作的函數(shù)或者方法。
當(dāng)和槽連接的信號(hào)被發(fā)射時(shí),槽會(huì)被調(diào)用。一個(gè)槽并不知道是否有任何信號(hào)與自己相連接。
信號(hào)與槽機(jī)制:主要分兩種
手動(dòng)操作:信號(hào)連接槽
自動(dòng)操作:當(dāng)信號(hào)發(fā)出時(shí),連續(xù)的槽函數(shù)會(huì)自動(dòng)執(zhí)行
信號(hào)連接
通過調(diào)用 QObject 對(duì)象的 connect 函數(shù)來將某個(gè)對(duì)象的信號(hào)與另外一個(gè)對(duì)象的槽函數(shù)相關(guān)聯(lián),這樣當(dāng)發(fā)射者發(fā)射信號(hào)時(shí),接收者的槽函數(shù)將被調(diào)用。該函數(shù)的定義如下:
object.信號(hào).connet(槽函數(shù))
當(dāng)信號(hào)與槽沒有必要繼續(xù)保持關(guān)聯(lián)時(shí),可以使用 disconnect 函數(shù)來斷開連接。其定義如下:
disconnect(槽函數(shù))
信號(hào)和槽的特點(diǎn):
1.一個(gè)信號(hào)可以連接到多個(gè)槽:當(dāng)信號(hào)發(fā)出后,槽函數(shù)都會(huì)被調(diào)用,但是調(diào)用的順序是隨機(jī)的,不確定的。
2.多個(gè)信號(hào)可以連接到同一個(gè)槽:其中任何一個(gè)信號(hào)發(fā)出,槽函數(shù)都會(huì)被執(zhí)行。
3.信號(hào)的參數(shù)可以是任何的Python類型,如list,dict等python獨(dú)有的類型。自定義信號(hào)的時(shí)候舉例說明。
4.信號(hào)和槽的連接可以被移除:比如斷開某個(gè)特定信號(hào)的關(guān)聯(lián)。
5.信號(hào)可以和另外一個(gè)信號(hào)進(jìn)行關(guān)聯(lián):第一個(gè)信號(hào)發(fā)出后,第二個(gè)信號(hào)也同時(shí)發(fā)送。比如關(guān)閉系統(tǒng)的信號(hào)發(fā)出之后,同時(shí)會(huì)發(fā)出保存數(shù)據(jù)的信號(hào)。
二、代碼樣例
整體代碼如下:
import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,QGridLayout,QLabel,QHBoxLayout, QGroupBox, QVBoxLayout, QApplication,QProgressBar,QPushButton,QMessageBox) class SignalSlot(QWidget): def __init__(self): super(SignalSlot,self).__init__() self.initUI() def initUI(self): self.controlsGroup = QGroupBox("運(yùn)行樣本") self.lcdNumber = QLCDNumber(self) self.slider = QSlider(Qt.Horizontal, self) self.pBar = QProgressBar(self) vbox = QVBoxLayout() vbox.addWidget(self.pBar) vbox.addWidget(self.lcdNumber) vbox.addWidget(self.slider) self.controlsGroup.setLayout(vbox) controlsLayout = QGridLayout() self.label1 = QLabel("保存狀態(tài):") self.saveLabel = QLabel() self.label2 = QLabel("運(yùn)行狀態(tài):") self.runLabel = QLabel() self.buttonSave = QPushButton("保存") self.buttonRun = QPushButton("運(yùn)行") self.buttonStop = QPushButton("停止") self.buttonDisconnect = QPushButton("解除關(guān)聯(lián)") self.buttonConnect = QPushButton("綁定關(guān)聯(lián)") controlsLayout.addWidget(self.label1,0,0) controlsLayout.addWidget(self.saveLabel,0,1) controlsLayout.addWidget(self.label2,1,0) controlsLayout.addWidget(self.runLabel,1,1) controlsLayout.addWidget(self.buttonSave,2,0) controlsLayout.addWidget(self.buttonRun,2,1) controlsLayout.addWidget(self.buttonStop,2,2) controlsLayout.addWidget(self.buttonDisconnect,3,0) controlsLayout.addWidget(self.buttonConnect,3,1) layout = QHBoxLayout() layout.addWidget(self.controlsGroup) layout.addLayout(controlsLayout) self.setLayout(layout) self.buttonRun.clicked.connect(self.buttonSave.clicked) self.slider.valueChanged.connect(self.pBar.setValue) self.slider.valueChanged.connect(self.lcdNumber.display) self.buttonSave.clicked.connect(self.showMessage) self.buttonRun.clicked.connect(self.showMessage) self.buttonDisconnect.clicked.connect(self.unbindConnection) self.buttonConnect.clicked.connect(self.bindConnection) self.buttonStop.clicked.connect(self.stop) self.setGeometry(300, 500, 500, 180) self.setWindowTitle('信號(hào)和槽') def showMessage(self): if self.sender().text() == "保存": self.saveLabel.setText("Saved") elif self.sender().text() == "運(yùn)行": self.runLabel.setText("Running") def unbindConnection(self): self.slider.valueChanged.disconnect() def bindConnection(self): def stop(self): self.saveLabel.setText("") self.runLabel.setText("") if __name__ == '__main__': app = QApplication(sys.argv) ex = SignalSlot() ex.show() sys.exit(app.exec_())
控件說明:
控件類型 | 控件名稱 | 作用 |
---|---|---|
controlsGroup | QGroupBox | 為構(gòu)建分組框提供了支持。分組框通常帶有一個(gè)邊框和一個(gè)標(biāo)題欄,作為容器部件來使用,在其中可以布置各種窗口部件。 |
lcdNumber | QLCDNumber | 用于顯示一個(gè)帶有類似液晶顯示屏效果的數(shù)字。 |
slider | QSlider | 提供一個(gè)垂直或者水平的滑動(dòng)條,滑動(dòng)條是一個(gè)用于控制有界值典型的控件,它允許用戶沿水平或者垂直方向在某一范圍內(nèi)移動(dòng)滑塊,并將滑塊所在的位置轉(zhuǎn)換為一個(gè)合法范圍內(nèi)的整數(shù)值 |
pBar | QProgressBar | 提供了一個(gè)水平或垂直的進(jìn)度條 |
label1 | QLabel |
|
buttonSave | QPushButton | 常用的按鈕控件 |
界面說明:
程序樣本運(yùn)行的界面邏輯,先設(shè)定運(yùn)行的程序樣本數(shù)量,然后先保存后運(yùn)行的邏輯狀態(tài)。通過slider的滑動(dòng)來改變progressBar和LCD的顯示數(shù)據(jù);“保存”按鈕保存運(yùn)行的樣本;“運(yùn)行”按鈕運(yùn)行程序樣本;“解除關(guān)聯(lián)”解除slider.valueChanged信號(hào)的綁定,此時(shí)slider的滑動(dòng),不會(huì)改變progressBar和LCD的顯示。
self.controlsGroup = QGroupBox("運(yùn)行樣本") self.lcdNumber = QLCDNumber(self) self.slider = QSlider(Qt.Horizontal, self) self.pBar = QProgressBar(self) vbox = QVBoxLayout() vbox.addWidget(self.pBar) vbox.addWidget(self.lcdNumber) vbox.addWidget(self.slider) self.controlsGroup.setLayout(vbox)
實(shí)例化一個(gè)QGroupBox,在其中添加QProgressBar、QLCDNumber、QSlider控件。
controlsLayout = QGridLayout() self.label1 = QLabel("保存狀態(tài):") self.saveLabel = QLabel() self.label2 = QLabel("運(yùn)行狀態(tài):") self.runLabel = QLabel() self.buttonSave = QPushButton("保存") self.buttonRun = QPushButton("運(yùn)行") self.buttonStop = QPushButton("停止") self.buttonDisconnect = QPushButton("解除關(guān)聯(lián)") self.buttonConnect = QPushButton("綁定關(guān)聯(lián)") controlsLayout.addWidget(self.label1,0,0) controlsLayout.addWidget(self.saveLabel,0,1) controlsLayout.addWidget(self.label2,1,0) controlsLayout.addWidget(self.runLabel,1,1) controlsLayout.addWidget(self.buttonSave,2,0) controlsLayout.addWidget(self.buttonRun,2,1) controlsLayout.addWidget(self.buttonStop,2,2) controlsLayout.addWidget(self.buttonDisconnect,3,0) controlsLayout.addWidget(self.buttonConnect,3,1)
通過QGridLayout()添加標(biāo)簽以及按鈕。
layout = QHBoxLayout() layout.addWidget(self.controlsGroup) layout.addLayout(controlsLayout) self.setLayout(layout)
最后通過QHBoxLayout將左右兩個(gè)界面合并,形成最終界面。
信號(hào)與槽說明:
signal和slot進(jìn)行綁定。
1.一個(gè)信號(hào)綁定多個(gè)槽:
self.slider.valueChanged.connect(self.pBar.setValue) self.slider.valueChanged.connect(self.lcdNumber.display)
slider控件的valueChanged信號(hào),同時(shí)與QProgressBar的setValue(),QLCDNumber的display()槽函數(shù)綁定,當(dāng)valueChanged信號(hào)觸發(fā)的時(shí)候,這兩個(gè)槽函數(shù)均會(huì)被調(diào)用。
2.多個(gè)信號(hào)綁定到一個(gè)槽:
self.buttonSave.clicked.connect(self.showMessage) self.buttonRun.clicked.connect(self.showMessage)
buttonSave和buttonRun這兩個(gè)對(duì)象的clicked信號(hào),同時(shí)綁定到showMessage()這個(gè)槽函數(shù)。無論哪一個(gè)信號(hào)被觸發(fā),showMessage()這個(gè)槽函數(shù)均會(huì)被調(diào)用,而根據(jù)self.sender().text() 這個(gè)函數(shù)來判斷顯示的不同內(nèi)容。
3.信號(hào)和槽的連接可以被移除:
self.buttonDisconnect.clicked.connect(self.unbindConnection)
當(dāng)buttonDisconnect信號(hào)觸發(fā)之后,與其關(guān)聯(lián)的槽函數(shù)unbindConnection()中就會(huì)執(zhí)行disconnect()方法,如下:
def unbindConnection(self): self.slider.valueChanged.disconnect()
其中執(zhí)行disconnect()的時(shí)候可以指定解除與某個(gè)特定的slot槽的關(guān)聯(lián),比如self.slider.valueChanged.disconnect(self.pBar.setValue),此時(shí)解除和QProgressBar的setValue()的關(guān)聯(lián),如果不指定,將解除和這個(gè)信號(hào)所有關(guān)聯(lián)的槽。
4、信號(hào)與信號(hào)的關(guān)聯(lián):
self.buttonRun.clicked.connect(self.buttonSave.clicked)
在樣例說明中提到,在運(yùn)行之前要對(duì)樣本進(jìn)行保存,所以為了保證運(yùn)行的時(shí)候執(zhí)行了保存的操作,所以將buttonRun.clicked信號(hào)和buttonSave.clicked信號(hào)關(guān)聯(lián)起來。
示例中在沒有執(zhí)行“保存”(buttonSave)的時(shí)候,執(zhí)行“運(yùn)行”(buttonRun),此時(shí)由于兩個(gè)對(duì)象的clicked信號(hào)已經(jīng)關(guān)聯(lián),所以buttonSave的clicked同樣會(huì)執(zhí)行。
最終結(jié)果:
本文是《從零開始學(xué)PyQt5》第五篇,希望小伙伴們可以多多支持,一起學(xué)習(xí)!
參考:
Pyqt5系列(七)-信號(hào)與槽機(jī)制_追逐陽光的風(fēng)-CSDN博客_pyqt5信號(hào)和槽
到此這篇關(guān)于PyQt5信號(hào)與槽機(jī)制案例詳解的文章就介紹到這了,更多相關(guān)PyQt5信號(hào)與槽機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 3.x基礎(chǔ)實(shí)戰(zhàn)檢查磁盤可用空間
這篇文章主要為大家介紹了Python 3.x基礎(chǔ)實(shí)戰(zhàn)之檢查磁盤可用空間實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05聯(lián)邦學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)FedAvg算法實(shí)現(xiàn)
這篇文章主要為大家介紹了聯(lián)邦學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)FedAvg算法實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05python smtplib模塊自動(dòng)收發(fā)郵件功能(一)
這篇文章主要為大家詳細(xì)介紹了python smtplib模塊自動(dòng)收發(fā)郵件功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05python 獲取頁面表格數(shù)據(jù)存放到csv中的方法
今天小編就為大家分享一篇python 獲取頁面表格數(shù)據(jù)存放到csv中的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-12-12Python實(shí)現(xiàn)光速定位并提取兩個(gè)文件的不同之處
如果你經(jīng)常與Excel或Word打交道,那么從兩份表格/文檔中找到不一樣的元素是一件讓人很頭疼的工作。本文就將以兩份真實(shí)的Excel/Word文件為例,講解如何使用Python光速對(duì)比并提取文件中的不同之處2022-08-08Python實(shí)現(xiàn)屏幕代碼雨效果的示例代碼
這篇文章主要介紹了如何利用Python中的Pygame模塊實(shí)現(xiàn)代碼雨效果,文中通過示例代碼介紹的非常詳細(xì),感興趣的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-03-03python 正則表達(dá)式參數(shù)替換實(shí)例詳解
這篇文章主要介紹了python 正則表達(dá)式參數(shù)替換,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01