2.PyQt5程序信号与槽
2.1信号与槽概述
信号与槽是Qt编程的基础,也是Qt的一大特色功能。
信号是在特定情况下被发射的一种通知,如:按钮的单击发射clicked信号;
槽是对信号响应的函数,其本质上是一个函数,也可以被直接调用;
槽函数可以与信号关联,当信号被发射时关联的槽函数会被触发执行;
2.2PyQt5 GUI应用程序设计的完整过程
1.在Qt Creator中设计窗体
2.设置组件的信号与槽函数的关联
3.设计窗体组件的响应槽函数
示例:界面设计如下:
实现:选择复选框或单选按钮时,对应显示选择结果;清除按钮将显示结果清除掉,确定和关闭按钮将窗口关闭。
第1步:在PyCharm中新建工程项目
第2步:在QtCreator中新建工程项目,选择基类为QDialog,Qt项目保存位置为PyCharm新建的项目下,工程名称定义为QtApp,绘制界面,并设置组件属性如下:
objectName | 类名称 | 属性设置 | 说明 |
---|---|---|---|
groupBox | QGroupBox | title=“您喜欢的编程语言” | 设置QGroupBox的标题 |
checkBoxPython | QCheckBox | text="Python" | 设置QCheckBox的显示文本 |
checkBoxC | QCheckBox | text="C" | 设置QCheckBox的显示文本 |
checkBoxCpp | QCheckBox | text="C++" | 设置QCheckBox的显示文本 |
checkBoxJava | QCheckBox | text="Java" | 设置QCheckBox的显示文本 |
checkBoxGo | QCheckBox | text="Go" | 设置QCheckBox的显示文本 |
checkBoxOther | QCheckBox | text="其他" | 设置QCheckBox的显示文本 |
groupBox_2 | QGroupBox | title=“您的性别” | 设置QGroupBox的标题 |
radioButtonBoy | QRadioButton | text="男" | 设置QRadioButton的显示文本 |
radioButtonGirl | QRadioButton | text="女" | 设置QRadioButton的显示文本 |
textBrowserSex | QTextBrowser | ||
textBrowserLang | QTextBrowser | ||
pushButtonClear | QPushButton | text="清除" | 设置QPushButton显示文本 |
pushButtonOk | QPushButton | text="确定" | 设置QPushButton显示文本 |
pushButtonClose | QPushButton | text="关闭" | 设置QPushButton显示文本 |
第3步:设置按钮组件与内建槽函数关联
Qt界面组件都有一些内建的信号与槽函数。在本例中,我们来看一下按钮的单击信号clicked,在单击时发射,我们刚才在创建项目时选择的基类为QDialog,QDialog具有以下内建的槽函数:
-
accept()
关闭对话框,用来表示肯定的选择
-
reject()
关闭对话框,用来表示否定的选择
-
close()
关闭对话框
在QtCreator中,设置确定按钮的clicked信号与窗体的accept()关联;设置关闭按钮的clicked信号与窗体的close()关联。设置好后直接在QtCreator中运行程序可以看到,单击确定和关闭按钮都可以将对话框窗体关闭掉。
第4步:在PyCharm创建的项目中创建一个批处理程序uic.bat,负责将.ui文件转换为.py文件
其内容为:
echo off copy .\QtApp\dialog.ui .\dialog.ui pyuic5 -o ui_dialog.py dialog.ui
执行uic.bat后可以看到在项目文件夹下会生成ui_dialog.py文件。
打开ui_dialog.py文件,可以看到刚才设置信号与槽函数关联的代码:
self.pushButtonOk.clicked.connect(Dialog.accept) # type: ignore self.pushButtonClose.clicked.connect(Dialog.close) # type: ignore
信号与槽关联使用connect()函数:
sender.signalName.connect(receiver.slotName)
其中:
-
sender
发射信号的对象
-
signalName
信号名称
-
receiver
接受信号的对象
-
slotName
槽函数名称
第4步:编写主程序并执行
# coding: utf-8 import sys from PyQt5.QtWidgets import QDialog, QApplication from ui_dialog import Ui_Dialog class QAppDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.__ui = Ui_Dialog() self.__ui.setupUi(self) if __name__ == '__main__': app = QApplication(sys.argv) dialog = QAppDialog() dialog.show() sys.exit(app.exec_())
运行程序后,我们可以看到单击确定和关闭按钮都可以关闭窗体,但我们在这里没有编写代码,那是因为我在设计界面的时候进行了信号和槽的关联,在生成的ui_dialog.py文件中已经自动生成了信号和槽的关联。
第5步:设置自动关联的槽函数
什么是自动关联的槽函数呢?我们再次打开ui_dialog.py文件,在setupUi函数中会看到这样一行代码:
QtCore.QMetaObject.connectSlotsByName(Dialog)
这样代码中,使用了Qt的元对象 QMetaObject ,该对象会搜索Dialog窗体上的所有从属组件,将匹配信号和槽函数关联起来,它假定的槽函数名称为:
on_<对象名>_<信号>(<信号参数>)
我们可以根据这个规则在业务类中编写相应的函数即可自动被关联执行。也可以在QtCreator中进行操作,然后使用QtCreator帮助我们生成的函数名。下面,我们先来编写“清空”按钮的槽函数,在QtCreator中打开窗体dialog.ui文件,选中“清空”按钮右击,在弹出菜单中选择“Go to slot...”,然后选择信号clicked,单击“OK”按钮,这样,在QtCreator中生成如下代码:
void Dialog::on_pushButtonClear_clicked() { }
我们在这里不编写代码,主要是使用其自动生成的函数名称,在PyCharm项目中QAppDialog类中定义on_pushButtonClear_clicked函数并编写代码:
def on_pushButtonClear_clicked(self): self.__ui.textBrowserSex.clear() self.__ui.textBrowserLang.clear()
为了演示程序,我们现在在QAppDialog类的构造函数中,增加两行代码:
self.__ui.textBrowserSex.setText("女") self.__ui.textBrowserLang.setText("Python")
现在运行程序,单击“清除”按钮后可以看到显示文字的文本框中被清空了。
第6步:overload型信号处理
现在,我们来处理性别数据,目标是当选择性别为男或女的时候,将textBrowserSex中的文本设置为:“您的性别:男”或者是“您的性别:女”。
同样在QtCreator中QRadioButton的“Go to slot...”对话框中,可以看到有两个名称为clicked信号,那么,我们现在处理clicked(bool)信号,在PyCharm项目中QAppDialog类中按照规则添加一个方法:
on_radioButtonBoy_clicked(self, checked)
代码如下:
def on_radioButtonBoy_clicked(self, checked): if checked: self.__ui.textBrowserSex.setText("您的性别:{0}".format("男"))
运行程序后,发现当选择性别“男”的时候程序发生异常。原因是connectSlotsByName()函数默认关联的是clicked()信号,而不是clicked(bool)信号。所以需要使用@pyqtSlot装饰符。修改程序如下:
@pyqtSlot(bool) def on_radioButtonBoy_clicked(self, checked): if checked: self.__ui.textBrowserSex.setText("您的性别:{0}".format("男"))
pyqtSlot装饰符需要导入:
from PyQt5.QtCore import pyqtSlot
同样的方法对性别“女”的QRadioButton编写代码:
@pyqtSlot(bool) def on_radioButtonGirl_clicked(self, checked): if checked: self.__ui.textBrowserSex.setText("您的性别:{0}".format("女"))
第7步:手动关联信号与槽函数
下面,对编程语言一栏进行处理,我们希望所有的QCheckBox使用一个方法来统一处理。所以首先需要手动将组件与槽函数关联,我们确定的槽函数名为do_selectLang(),在QAppDialog类的构造函数中添加代码如下:
self.__ui.checkBoxPython.clicked.connect(self.do_selectLang) self.__ui.checkBoxC.clicked.connect(self.do_selectLang) self.__ui.checkBoxCpp.clicked.connect(self.do_selectLang) self.__ui.checkBoxGo.clicked.connect(self.do_selectLang) self.__ui.checkBoxJava.clicked.connect(self.do_selectLang) self.__ui.checkBoxOther.clicked.connect(self.do_selectLang)
编写槽函数do_selectLang,代码如下:
def do_selectLang(self): langs = [] if self.__ui.checkBoxPython.isChecked(): langs.append("Python") if self.__ui.checkBoxC.isChecked(): langs.append("C") if self.__ui.checkBoxCpp.isChecked(): langs.append("C++") if self.__ui.checkBoxGo.isChecked(): langs.append("Go") if self.__ui.checkBoxJava.isChecked(): langs.append("Java") if self.__ui.checkBoxOther.isChecked(): langs.append("其他") self.__ui.textBrowserLang.setText("您喜欢的编程语言:{0}".format(",".join(langs)))
以上就是整个示例程序的设计过程,在本文中没有表述QtCreator中进行界面设计的过程,请读者自行学习和摸索。