在PyQt设计中,多界面交互或线程交互不可避免的会用到信号与槽函数,因为要避免将全部任务交给主线程处理,导致主线程阻塞界面卡顿,下面以一个两窗口交互的例子简要介绍一下信号与槽函数的基本用法。
这里利用QtDesigner设计了两个界面,一个MainWindow和一个Dialog。
代码如下(命名为windows.py):
from PyQt5 import QtCore, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(467, 276)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setObjectName("textEdit")
self.verticalLayout.addWidget(self.textEdit)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.verticalLayout.addLayout(self.horizontalLayout)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "主窗口"))
self.pushButton.setText(_translate("MainWindow", "打开子窗口"))
class Ui_ChildWindow(object):
def setupUi(self, ChildWindow):
ChildWindow.setObjectName("ChildWindow")
ChildWindow.resize(330, 116)
self.gridLayout = QtWidgets.QGridLayout(ChildWindow)
self.gridLayout.setObjectName("gridLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.lineEdit = QtWidgets.QLineEdit(ChildWindow)
self.lineEdit.setObjectName("lineEdit")
self.horizontalLayout.addWidget(self.lineEdit)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.verticalLayout.addLayout(self.horizontalLayout)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem2)
self.pushButton = QtWidgets.QPushButton(ChildWindow)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout_2.addWidget(self.pushButton)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem3)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
self.retranslateUi(ChildWindow)
QtCore.QMetaObject.connectSlotsByName(ChildWindow)
def retranslateUi(self, ChildWindow):
_translate = QtCore.QCoreApplication.translate
ChildWindow.setWindowTitle(_translate("ChildWindow", "子窗口"))
self.pushButton.setText(_translate("ChildWindow", "发送文本"))
然后在主函数(main.py)中,通过继承的方式使用这两个窗口。
代码如下:
from windows import Ui_MainWindow, Ui_ChildWindow
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow
import sys
class MainWindow(Ui_MainWindow, QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.openChildWindow)
self.childWindow = ChildWindow()
self.childWindow.sig.connect(self.receiveSignal)
def openChildWindow(self):
self.childWindow.show()
def receiveSignal(self, text):
# 槽函数
self.textEdit.insertPlainText(text)
class ChildWindow(Ui_ChildWindow, QDialog):
sig = pyqtSignal(str) # 信号
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.emitSignal)
def emitSignal(self):
self.sig.emit(self.lineEdit.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
其中,“sig = pyqtSignal(str)”即是我们定义的信号,该信号发送字符串数据,定义在了子窗口ChildWindow中。
在主窗口MainWindow中,我们首先初始化了一个子窗口ChildWindow对象,然后将该对象中的信号sig通过connect方法连接到主窗口的槽函数receiveSignal中,该函数执行时text参数被赋予信号所发来的字符串,这样就建立了一个简单的主窗口和子窗口的交互渠道。
在子窗口中,定义了一个emitSignal方法,在该方法中,信号sig通过emit方法发射lineEdit中获取到的字符串。该方法被连接到按钮pushButton上。当按钮按下后,即可发出字符串,随后主窗口中的receiveSignal方法响应该信号,执行其中的动作,即将收到的字符串插入textEdit中。