一文詳解PyQt5中信號(hào)(Signal)與槽(Slot)
信號(hào)與槽介紹
信號(hào)(Signal)與槽(Slot)是Qt中的核心機(jī)制,也是在PyQt編程中對(duì)象之間進(jìn)行通信的機(jī)制。PyQt的窗口控件類(lèi)有很多內(nèi)置信號(hào),開(kāi)發(fā)者也可以添加自定義信號(hào)。信號(hào)與槽有如下特點(diǎn):
- 一個(gè)信號(hào)可以連接多個(gè)槽。
- 一個(gè)信號(hào)可以連接另一個(gè)信號(hào)。
- 信號(hào)參數(shù)可以使任何Python類(lèi)型。
- 一個(gè)槽可以連接到多個(gè)信號(hào)。
- 信號(hào)與槽的連接方式可以是同步連接,也可以是異步連接。
- 信號(hào)與槽的連接可能會(huì)跨線程。
- 信號(hào)可以斷開(kāi)連接。
內(nèi)置信號(hào)與槽的使用
這里演示了內(nèi)置clicked信號(hào)連接槽函數(shù)的使用
import sys
from PyQt5.QtWidgets import QPushButton, QApplication, QWidget, QMessageBox
app = QApplication(sys.argv)
widget = QWidget()
def showMsg():
QMessageBox.information(widget, "信息提示框", "Ok,彈出測(cè)試信息")
btn = QPushButton("測(cè)試點(diǎn)擊按鈕", widget)
btn.clicked.connect(showMsg)
widget.show()
sys.exit(app.exec_())

自定義信號(hào)與槽的使用
import sys
from PyQt5.QtCore import QObject, pyqtSignal
# 信號(hào)對(duì)象
class QTypeSignal(QObject):
# 定義一個(gè)信號(hào)
sendmsg = pyqtSignal(object)
def __init__(self):
super(QTypeSignal, self).__init__()
def run(self):
# 發(fā)射信號(hào)
self.sendmsg.emit('Hello PyQt5')
# 槽對(duì)象
class QTypeSlot(QObject):
def __init__(self):
super(QTypeSlot, self).__init__()
# 槽對(duì)象中的槽函數(shù)
def get(self, msg):
print("QSlot get msg => " + msg)
if __name__ == "__main__":
send = QTypeSignal()
slot = QTypeSlot()
# 1
print("---把信號(hào)綁定到槽函數(shù)上---")
send.sendmsg.connect(slot.get)
send.run()
# 2
print('---把信號(hào)與槽函數(shù)斷開(kāi)---')
send.sendmsg.disconnect(slot.get)
send.run()

自定義信號(hào)和內(nèi)置槽函數(shù)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtCore import Qt
class WinForm (QWidget):
# 自定義信號(hào),不帶參數(shù)
button_clicked_signal = pyqtSignal()
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.setWindowTitle("自定義信號(hào)和內(nèi)置槽函數(shù)示例")
self.resize(330, 50)
btn = QPushButton("關(guān)閉", self)
# 連接信號(hào)與槽函數(shù)
btn.clicked.connect(self.btn_clicked)
# 接收信號(hào),連接到槽函數(shù)
self.button_clicked_signal.connect(self.close)
def btn_clicked(self):
# 發(fā)送自定義信號(hào),無(wú)參數(shù)
self.button_clicked_signal.emit()
if __name__ == "__main__":
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec_())
自定義信號(hào)和自定義槽函數(shù)
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class WinForm(QWidget):
# 自定義信號(hào),無(wú)參數(shù)
button_clicked_signal = pyqtSignal()
def __init__(self, parent= None):
super(WinForm, self).__init__(parent)
self.setWindowTitle("自定義信號(hào)和槽函數(shù)示例")
self.resize(350, 50)
btn = QPushButton("關(guān)閉", self)
btn.clicked.connect(self.btn_clicked)
self.button_clicked_signal.connect(self.btn_close)
def btn_clicked(self):
self.button_clicked_signal.emit()
def btn_close(self):
self.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec_())
自定義有參信號(hào)
import sys
from PyQt5.QtCore import pyqtSignal, QObject
class CustSignal(QObject):
# 聲明無(wú)參數(shù)的信號(hào)
signal1 = pyqtSignal()
# 聲明帶一個(gè)int類(lèi)型參數(shù)的信號(hào)
signal2 = pyqtSignal(int)
# 聲明帶一個(gè)int和一個(gè)str類(lèi)型參數(shù)的信號(hào)
signal3 = pyqtSignal(int, str)
# 聲明帶一個(gè)列表類(lèi)型參數(shù)的信號(hào)
signal4 = pyqtSignal(list)
# 聲明帶一個(gè)字典類(lèi)型參數(shù)的信號(hào)
signal5 = pyqtSignal(dict)
# 聲明一個(gè)多重載版本的信號(hào),包括帶int和str類(lèi)型參數(shù)的信號(hào)和帶str類(lèi)型參數(shù)的信號(hào)
signal6 = pyqtSignal([int,str], [str])
def __init__(self, parent=None):
super(CustSignal, self).__init__(parent)
# 將信號(hào)連接到指定的槽函數(shù)
self.signal1.connect(self.signalCall1)
self.signal2.connect(self.signalCall2)
self.signal3.connect(self.signalCall4)
self.signal4.connect(self.signalCall4)
self.signal5.connect(self.signalCall5)
self.signal6[int, str].connect(self.signalCall6)
self.signal6[str].connect(self.signalCall6OverLoad)
# 發(fā)射信號(hào)
self.signal1.emit()
self.signal2.emit(100)
self.signal3.emit(200, 'hello')
self.signal4.emit([1,2,3,4,5,6])
self.signal5.emit({"name":"xiaowang", "age":"25"})
self.signal6[int, str].emit(300, 'hello world')
self.signal6[str].emit('hello pyqt')
def signalCall1(self):
print('signal1 emit')
def signalCall2(self, val):
print('signal3 emit, value:', val)
def signalCall3(self, val, text):
print('signal3 emit, value:', val, text)
def signalCall4(self, val):
print('signal4 emit, value:', val)
def signalCall5(self, val):
print('signal5 emit, value:', val)
def signalCall6(self, val, text):
print('signal6 emit, value:', val, text)
def signalCall6OverLoad(self, val):
print('signal6 overload emit, value:', val)
if __name__ == "__main__":
custSignal = CustSignal()
使用自定義信號(hào)參數(shù)
對(duì)于clicked信號(hào)來(lái)說(shuō)他是沒(méi)有參數(shù)的,如果連接的槽函數(shù)希望可以接收參數(shù),如果直接連接有參數(shù)的槽函數(shù)會(huì)出錯(cuò),因?yàn)樾盘?hào)發(fā)出的參數(shù)個(gè)數(shù)一定要大于槽函數(shù)接收的參數(shù)個(gè)數(shù)。這里有兩種解決方法:
1.使用lambda
2.使用functools模塊中的partial函數(shù)
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from functools import partial, partialmethod
class WinForm(QMainWindow):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.setWindowTitle("有參槽函數(shù)接收無(wú)參信號(hào)的解決方法")
button1 = QPushButton("Button 1")
button2 = QPushButton("Button 2")
# 對(duì)于clicked信號(hào)來(lái)說(shuō)他是沒(méi)有參數(shù)的,如果連接的槽函數(shù)希望可以接收參數(shù),如果直接連接有參數(shù)
# 的槽函數(shù)會(huì)出錯(cuò),因?yàn)樾盘?hào)發(fā)出的參數(shù)個(gè)數(shù)一定要大于槽函數(shù)接收的參數(shù)個(gè)數(shù)。這里有兩種解決方法:
# 1.使用lambda
# 2.使用functools模塊中的partial函數(shù)
# 使用lambda
button1.clicked.connect(lambda: self.onButtonClick(1))
# 使用functools模塊中的partial函數(shù)
button2.clicked.connect(partial(self.onButtonClick, 2))
layout = QHBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
mainwidget = QWidget()
mainwidget.setLayout(layout)
self.setCentralWidget(mainwidget)
def onButtonClick(self, n):
print("Button {0} 被按下了".format(n))
QMessageBox.information(self, "信息提示框", 'Button {0} clicked'.format(n))
if __name__ == "__main__":
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec_())
裝飾器信號(hào)與槽
@PyQt5.QtCore.pyqtSlot(參數(shù))
def on_發(fā)送者對(duì)象名稱(chēng)_發(fā)射信號(hào)名稱(chēng)(self, 參數(shù)):
pass
必須先執(zhí)行了這行代碼:QtCore.QMetaObject.connectSlotsByName(self)
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QMessageBox
import sys
# 裝飾器信號(hào)與槽
# @PyQt5.QtCore.pyqtSlot(參數(shù))
# def on_發(fā)送者對(duì)象名稱(chēng)_發(fā)射信號(hào)名稱(chēng)(self, 參數(shù)):
# pass
#
# 必須要先執(zhí)行這行代碼:QtCore.QMetaObject.connectSlotsByName(self)
class CustWidget(QWidget):
def __init__(self, parent=None):
super(CustWidget, self).__init__(parent)
self.setWindowTitle("裝飾器信號(hào)與槽Demo")
self.resize(350, 50)
self.okButton = QPushButton("OK", self)
# 使用setObjectName設(shè)置對(duì)象名稱(chēng)
self.okButton.setObjectName("okButton")
layout = QHBoxLayout()
layout.addWidget(self.okButton)
self.setLayout(layout)
QtCore.QMetaObject.connectSlotsByName(self)
@QtCore.pyqtSlot()
def on_okButton_clicked(self):
print("單擊了OK按鈕")
QMessageBox.information(self, "信息提示框", "單擊了OK按鈕")
if __name__ == "__main__":
app = QApplication(sys.argv)
win = CustWidget()
win.show()
sys.exit(app.exec_())
信號(hào)與槽的斷開(kāi)和連接
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# 信號(hào)與槽斷開(kāi)連接
class SignalClass(QObject):
# 聲明無(wú)參數(shù)的信號(hào)
signal1 = pyqtSignal()
# 聲明帶一個(gè)int類(lèi)型參數(shù)的信號(hào)
signal2 = pyqtSignal(int)
def __init__(self, parent=None):
super(SignalClass, self).__init__(parent)
# 將信號(hào)signal1連接到sig1Call和sig2Call這兩個(gè)槽函數(shù)
self.signal1.connect(self.sig1Call)
self.signal1.connect(self.sig2Call)
# 將signal2連接到signal1
self.signal2.connect(self.signal1)
# 發(fā)射信號(hào)
self.signal1.emit()
self.signal2.emit(1)
# 斷開(kāi)signal1,signal2信號(hào)與各槽函數(shù)的連接
self.signal1.disconnect(self.sig1Call)
self.signal1.disconnect(self.sig2Call)
self.signal2.disconnect(self.signal1)
# 將信號(hào)signal1和signal2連接到同一個(gè)槽函數(shù)sig1Call
self.signal1.connect(self.sig1Call)
self.signal2.connect(self.sig1Call)
# 再次發(fā)射信號(hào)
self.signal1.emit()
self.signal2.emit(2)
def sig1Call(self):
print('signal-1 emit')
def sig2Call(self):
print('signal-2 emit')
if __name__ == "__main__":
signal = SignalClass()
多線程中信號(hào)與槽的使用
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QThread, pyqtSignal
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
# 創(chuàng)建一個(gè)線程實(shí)例并設(shè)置名稱(chēng),變量,信號(hào)與槽
self.thread = MyThread()
self.thread.setIdentity("thread1")
self.thread.sinOut.connect(self.outText)
self.thread.setVal(6)
def outText(self, text):
print(text)
class MyThread(QThread):
sinOut = pyqtSignal(str)
def __init__(self, parent=None):
super(MyThread, self).__init__(parent)
self.identity = None
def setIdentity(self, text):
self.identity = text
def setVal(self, val):
self.times = int(val)
# 執(zhí)行線程run方法
self.start()
def run(self):
while self.times > 0 and self.identity:
# 發(fā)射信號(hào)
self.sinOut.emit(self.identity + "==>" + str(self.times))
self.times -= 1
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
以上就是一文詳解PyQt5中信號(hào)(Signal)與槽(Slot)的詳細(xì)內(nèi)容,更多關(guān)于PyQt5信號(hào) 槽的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python爬蟲(chóng)之爬取筆趣閣小說(shuō)升級(jí)版
筆趣有很多起點(diǎn)中文網(wǎng)的小說(shuō),該網(wǎng)站小說(shuō)的更新速度稍滯后于起點(diǎn)中文網(wǎng)正版小說(shuō)的更新速度。并且該網(wǎng)站只支持在線瀏覽,不支持小說(shuō)打包下載。所以可以通過(guò)python爬取文本信息保存,從而達(dá)到下載的目的2021-09-09
python爬蟲(chóng)模擬瀏覽器訪問(wèn)-User-Agent過(guò)程解析
這篇文章主要介紹了python爬蟲(chóng)模擬瀏覽器訪問(wèn)-User-Agent過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Pandas的read_csv函數(shù)參數(shù)分析詳解
這篇文章主要介紹了Pandas的read_csv函數(shù)參數(shù)分析詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
python中?conda?虛擬環(huán)境管理和jupyter內(nèi)核管理
這篇文章主要介紹了python中?conda?虛擬環(huán)境管理和jupyter內(nèi)核管理,文章基于pyhton以及conda的虛擬環(huán)境創(chuàng)建、刪除、jupyter添加、刪除虛擬kernel的方法,需要的朋友可以參考一下2022-04-04
python3.8中關(guān)于sklearn問(wèn)題(win10)

