【Python】PyQt信号与槽函数

在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中。

信号与槽函数的好处

  1. 首先就是多界面交互时,一个界面无法获取到另一个界面中的内容,需要用到信号与槽函数来进行交互,因为不通窗口分属多个类,之间的属性不互通(除非一个类的对象是另一个类的属性,同时该对象中的属性不是私有的)。
  2. 即使一个类(下面称子窗口)的对象是另一个类(下面称主窗口)的属性,但如果主窗口想要做到及时获取子窗口的数据或执行方法,就要循环检查,这可能造成主窗口线程阻塞导致界面卡住。
  3. 多线程中,主线程或主窗口想要实时获得子线程的数据,而不是等子线程执行结束后再获取的话,需要用到信号与槽函数,子线程中不断发出信号,主窗口的槽函数实时响应该信号。

猜你喜欢

转载自blog.csdn.net/weixin_42147967/article/details/125515480
今日推荐