信号和槽
''' 信号(Signal)与槽(Slot) ''' from PyQt5.QtWidgets import * import sys class SigalSlotDemo(QWidget): def __init__(self): super(SigalSlotDemo,self).__init__() self.initUI() def onClick(self): self.btn.setText("信号已经发出") self.btn.setStyleSheet("QPushButton(max-200px;min-200px") def initUI(self): self.setGeometry(300, 300, 500, 400) self.setWindowTitle('信号(Signal)与槽(Slot)') self.btn = QPushButton('我的按钮',self) self.btn.clicked.connect(self.onClick) if __name__ == '__main__': app = QApplication(sys.argv) gui = SigalSlotDemo() gui.show() sys.exit(app.exec_())
自定义信号
''' 自定义信号 pyqtSignal() ''' from PyQt5.QtCore import * class MyTypeSignal(QObject): # 定义一个信号 sendmsg = pyqtSignal(object) # 发送3个参数的信号 sendmsg1 = pyqtSignal(str,int,int) def run(self): self.sendmsg.emit('Hello PyQt5') def run1(self): self.sendmsg1.emit("hello",3,4) class MySlot(QObject): def get(self,msg): print("信息:" + msg) def get1(self,msg,a,b): print(msg) print(a+b) if __name__ == '__main__': send = MyTypeSignal() slot = MySlot() send.sendmsg.connect(slot.get) send.sendmsg1.connect(slot.get1) send.run() send.run1() send.sendmsg.disconnect(slot.get) send.run()
为类添加多个信号
''' 为类添加多个信号 ''' from PyQt5.QtCore import * class MultiSignal(QObject): signal1 = pyqtSignal() signal2 = pyqtSignal(int) signal3 = pyqtSignal(int, str) signal4 = pyqtSignal(list) signal5 = pyqtSignal(dict) # 声明一个重载版本的信号,也就是槽函数的参数可以是int和str类型,也可以只有一个str类型的参数 signal6 = pyqtSignal([int,str],[str]) def __init__(self): super(MultiSignal,self).__init__() self.signal1.connect(self.signalCall1) self.signal2.connect(self.signalCall2) self.signal3.connect(self.signalCall3) self.signal4.connect(self.signalCall4) self.signal5.connect(self.signalCall5) self.signal6[str].connect(self.signalCall6Overload) self.signal6[int,str].connect(self.signalCall6) self.signal1.emit() self.signal2.emit(10) self.signal3.emit(1,"hello world") self.signal4.emit([1,2,3,4,5,6]) self.signal5.emit({"name":"Bill","age":30}) self.signal6[str].emit("test") self.signal6[int,str].emit(100,"mytest") def signalCall1(self): print("signal1 emit") def signalCall2(self,val): print("signal2 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__': multiSignal = MultiSignal()
信号槽N对N连接与断开连接
''' 信号槽N对N连接与断开连接 ''' from PyQt5.QtCore import * class NNSignal(QObject): signal1 = pyqtSignal() signal2 = pyqtSignal(int) signal3 = pyqtSignal() def __init__(self): super(NNSignal,self).__init__() self.signal1.connect(self.call1) self.signal1.connect(self.call11) self.signal3.connect(self.call1) self.signal1.emit() self.signal3.emit() ''' self.signal2.connect(self.signal1) self.signal2.emit(2) # 触发了信号1 self.signal1.disconnect(self.call1) self.signal1.disconnect(self.call11) self.signal2.disconnect(self.signal1) self.signal1.connect(self.call1) self.signal2.connect(self.call2) self.signal1.emit() self.signal2.emit(100) ''' def call1(self): print("call1 emit") def call11(self): print("call11 emit") def call2(self,val): print("call2 emit:",val) if __name__ == '__main__': nnSignal = NNSignal()
为窗口类添加信号
''' 为窗口类添加信号 ''' from PyQt5.QtWidgets import * from PyQt5.QtCore import * import sys class WinSignal(QWidget): button_clicked_signal = pyqtSignal() def __init__(self): super().__init__() self.setWindowTitle("为窗口类添加信号") self.resize(300,100) btn = QPushButton('关闭窗口',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) example = WinSignal() example.show() sys.exit(app.exec_())
多线程更新UI数据
''' 多线程更新UI数据(在两个线程中传递数据) ''' from PyQt5.QtCore import QThread , pyqtSignal, QDateTime from PyQt5.QtWidgets import QApplication, QDialog, QLineEdit import time import sys class BackendThread(QThread): update_date = pyqtSignal(str) def run(self): while True: data = QDateTime.currentDateTime() currentTime = data.toString("yyyy-MM-dd hh:mm:ss") self.update_date.emit(str(currentTime)) time.sleep(1) class ThreadUpdateUI(QDialog): def __init__(self): QDialog.__init__(self) self.setWindowTitle('多线程更新UI数据') self.resize(400,100) self.input = QLineEdit(self) self.input.resize(400,100) self.initUI() def initUI(self): self.backend = BackendThread() self.backend.update_date.connect(self.handleDisplay) self.backend.start() def handleDisplay(self,data): self.input.setText(data) if __name__ == '__main__': app = QApplication(sys.argv) example = ThreadUpdateUI() example.show() sys.exit(app.exec_())
信号与槽的自动连接
''' 信号与槽自动连接 on_objectname_signalname on_okButton_clicked ''' from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication ,QWidget ,QHBoxLayout , QPushButton import sys class AutoSignalSlot(QWidget): def __init__(self): super(AutoSignalSlot,self).__init__() self.okButton = QPushButton("ok",self) self.okButton.setObjectName("okButton") self.okButton1 = QPushButton("cancel",self) self.okButton1.setObjectName("cancelButton") layout = QHBoxLayout() layout.addWidget(self.okButton) self.setLayout(layout) QtCore.QMetaObject.connectSlotsByName(self) #self.okButton.clicked.connect(self.on_okButton_clicked) @QtCore.pyqtSlot() def on_okButton_clicked(self): print("点击了ok按钮") @QtCore.pyqtSlot() def on_cancelButton_clicked(self): print("点击了cancel按钮") if __name__ == '__main__': app = QApplication(sys.argv) example = AutoSignalSlot() example.show() sys.exit(app.exec_())
使用Lambda表达式为槽函数传递参数
''' 使用Lambda表达式为槽函数传递参数 Lambda表达式:匿名函数,也就是没有名字的函数 fun = lambda :print("hello world") fun() fun1 = lambda x,y:print(x,y) fun1("a","b") ''' from PyQt5.QtWidgets import * import sys class LambdaSlotArg(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("使用Lambda表达式为槽函数传递参数") button1 = QPushButton("按钮1") button2 = QPushButton("按钮2") ok = 100 button1.clicked.connect(lambda :self.onButtonClick(10,ok)) button2.clicked.connect(lambda :self.onButtonClick(ok,-20)) button1.clicked.connect(lambda :QMessageBox.information(self,"结果","单击了button1")) layout = QHBoxLayout() layout.addWidget(button1) layout.addWidget(button2) mainFrame = QWidget() mainFrame.setLayout(layout) self.setCentralWidget(mainFrame) def onButtonClick(self,m,n): print("m + n =",m + n ) QMessageBox.information(self,"结果",str(m+n)) if __name__ == "__main__": app = QApplication(sys.argv) form = LambdaSlotArg() form.show() sys.exit(app.exec_())
使用Partial对象为槽函数传递参数
''' 使用Partial对象为槽函数传递参数 ''' from PyQt5.QtWidgets import * import sys from functools import partial class PartialSlotArg(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("使用Partial表达式为槽函数传递参数") button1 = QPushButton("按钮1") button2 = QPushButton("按钮2") x = 20 y = -123 button1.clicked.connect(partial(self.onButtonClick,10,20)) button2.clicked.connect(partial(self.onButtonClick, x, y)) layout = QHBoxLayout() layout.addWidget(button1) layout.addWidget(button2) mainFrame = QWidget() mainFrame.setLayout(layout) self.setCentralWidget(mainFrame) def onButtonClick(self,m,n): print("m + n =",m + n ) QMessageBox.information(self,"结果",str(m+n)) if __name__ == "__main__": app = QApplication(sys.argv) form = PartialSlotArg() form.show() sys.exit(app.exec_())
Override(覆盖)槽函数
''' Override(覆盖)槽函数 ''' from PyQt5.QtWidgets import * from PyQt5.QtCore import * import sys class OverrideSlot(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Override(覆盖)槽函数") def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_Alt: self.setWindowTitle("按下Alt键") if __name__ == "__main__": app = QApplication(sys.argv) form = OverrideSlot() form.show() sys.exit(app.exec_())
多窗口交互
''' 多窗口交互(1):不使用信号与槽 Win1 Win2 ''' import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from DateDialog import DateDialog class MultiWindow1(QWidget): def __init__(self): super().__init__() self.setWindowTitle("多窗口交互(1):不使用信号与槽") self.lineEdit = QLineEdit(self) self.button1 = QPushButton('弹出对话框1') self.button1.clicked.connect(self.onButton1Click) self.button2 = QPushButton('弹出对话框2') self.button2.clicked.connect(self.onButton2Click) gridLayout = QGridLayout() gridLayout.addWidget(self.lineEdit) gridLayout.addWidget(self.button1) gridLayout.addWidget(self.button2) self.setLayout(gridLayout) def onButton1Click(self): dialog = DateDialog(self) result = dialog.exec() date = dialog.dateTime() self.lineEdit.setText(date.date().toString()) dialog.destroy() def onButton2Click(self): date,time,result = DateDialog.getDateTime() self.lineEdit.setText(date.toString()) if result == QDialog.Accepted: print('点击确定按钮') else: print('单击取消按钮') if __name__ == "__main__": app = QApplication(sys.argv) form = MultiWindow1() form.show() sys.exit(app.exec_())
多窗口交互(2):使用信号与槽
''' 多窗口交互(2):使用信号与槽 如果一个窗口A与另一个窗口B交互,那么A尽量不要直接访问B窗口中的控件, 应该访问B窗口中的信号,并指定与信号绑定的槽函数 例:如果A直接访问B窗口的控件,一旦B窗口控件发生改变,那么A和B的代码都需要变化 如果A访问的是B中的信号,那么B中的控件发生了改变,只需要修改B中的代码即可 ''' import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from NewDateDialog import NewDateDialog class MultiWindow2(QWidget): def __init__(self, parent=None): super(MultiWindow2, self).__init__(parent) self.resize(400, 90) self.setWindowTitle('多窗口交互(2):使用信号与槽') self.open_btn = QPushButton('获取时间') self.lineEdit_inner = QLineEdit(self) self.lineEdit_emit = QLineEdit(self) self.open_btn.clicked.connect(self.openDialog) self.lineEdit_inner.setText('接收子窗口内置信号的时间') self.lineEdit_emit.setText('接收子窗口自定义信号的时间') grid = QGridLayout() grid.addWidget(self.lineEdit_inner) grid.addWidget(self.lineEdit_emit) grid.addWidget(self.open_btn) self.setLayout(grid) def openDialog(self): dialog = NewDateDialog(self) # 连接子窗口的内置信号与主窗口的槽函数 dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot) # 连接子窗口的自定义信号与主窗口的槽函数 dialog.Signal_OneParameter.connect(self.deal_emit_slot) dialog.show() def deal_inner_slot(self, date): self.lineEdit_inner.setText(date.toString()) def deal_emit_slot(self, dateStr): self.lineEdit_emit.setText(dateStr) if __name__ == "__main__": app = QApplication(sys.argv) form = MultiWindow2() form.show() sys.exit(app.exec_())
DateDialog.py
from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class DateDialog(QDialog): def __init__(self,parent=None): super(DateDialog,self).__init__(parent) self.setWindowTitle("DateDialog") layout = QVBoxLayout(self) self.datetime = QDateTimeEdit(self) self.datetime.setCalendarPopup(True) self.datetime.setDateTime(QDateTime.currentDateTime()) layout.addWidget(self.datetime) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel,Qt.Horizontal,self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) def dateTime(self): return self.datetime.dateTime() @staticmethod def getDateTime(parent = None): dialog = DateDialog(parent) result = dialog.exec() date = dialog.dateTime() return (date.date(),date.time(),result == QDialog.Accepted)
NewDateDialog.py
from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class NewDateDialog(QDialog): Signal_OneParameter = pyqtSignal(str) def __init__(self, parent=None): super(NewDateDialog, self).__init__(parent) self.setWindowTitle('子窗口:用来发射信号') # 在布局中添加部件 layout = QVBoxLayout(self) self.label = QLabel(self) self.label.setText('前者发射内置信号 后者发射自定义信号') self.datetime_inner = QDateTimeEdit(self) self.datetime_inner.setCalendarPopup(True) self.datetime_inner.setDateTime(QDateTime.currentDateTime()) self.datetime_emit = QDateTimeEdit(self) self.datetime_emit.setCalendarPopup(True) self.datetime_emit.setDateTime(QDateTime.currentDateTime()) layout.addWidget(self.label) layout.addWidget(self.datetime_inner) layout.addWidget(self.datetime_emit) # 使用两个button(ok和cancel)分别连接accept()和reject()槽函数 buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) self.datetime_emit.dateTimeChanged.connect(self.emit_signal) def emit_signal(self): date_str = self.datetime_emit.dateTime().toString() self.Signal_OneParameter.emit(date_str)