第四篇 -- 信号与槽的使用

学习书籍《Python Qt GUI与数据可视化编程》

一、信号与槽功能概述

信号(Signal):就是在特定情况下被发射(emit)的一种通告,例如一个PushButton按钮最常见的信号就是鼠标单击时发射的clicked()信号,一个ComboBox最常见的信号是选择的项变化时发射的CurrentIndexChanged()信号。GUI程序设计的主要内容就是对界面上各组件发射的特定信号进行响应,只需要知道什么情况下发射了哪些信号,然后合理地去响应和处理这些信号就可以了。

槽(Slot):就是对信号响应的函数。槽实质上是一个函数,它可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数会被自动执行。Qt的类一般都有一些内建(build-in)的槽函数,例如QWidget有一个槽函数close(),其功能是关闭窗口。如果将一个PushButton按钮的clicked()信号与窗体的close()槽函数关联,那么点击按钮时就会关闭窗口。

二、组件的信号与内建槽函数的关联

1. 先画一个图

属性设置表格如下:

对象名 类名称 属性设置 功能
Dialog QDialog windowTitle="Demo2-3信号与槽" 窗体的类名称是Dialog,objectName不要修改
textEdit QPlainTextEdit

Text="PyQt5 编程指南 Python 和 Qt."

Font.PointSize=20

Font.bold=True

用于显示文字,可编辑
chkBoxUnder QCheckBox Text="Underline" 设置字体的下划线特定
chkBoxItalix QCheckBox Text="Italic" 设置字体的斜体特性
chkBoxBold QCheckBox Text="Bold" 设置字体的粗体特性
radioBlack QRadioButton Text="Black" 设置字体颜色为黑色
radioRed QRadioButton Text="Red" 设置字体颜色为红色
radioBlue QRadioButton Text="Blue" 设置字体颜色为蓝色
btnClear QPushButton Text="清空" 清空文本框内容
btnOK QPushButton Text="确定" 返回确定,并关闭窗口
btnClose QPushButton Text="退出" 退出程序

2. 界面组件布局管理

 

布局组件 功能
Vertival Layout 垂直布局,组件自动在垂直方向上分布
Horizontal Layout 水平布局,组件自动在水平方向上分布
Grid Layout 网格状布局,网格状布局大小改变时,每个网格的大小都改变
Form Layout 窗体布局,与网格布局类似。但是只有最右侧的一列网格会改变大小
Horizontal Spacer 一个用于水平分隔的空格
Vertical Spacer 一个用于垂直分隔的空格

使用:先拖一个布局组件到窗体上,例如窗体下方的3个按钮的布局,先放一个Horizontal Layout到窗体上,布局组件会以红色矩形框显示,在向布局组件里拖放3个PushButton和两个Horizontal Spacer,就可以得到3个按钮的水平布局。每个布局还有layoutTopMargin、layoutBottomMargin、layoutLeftMargin、layoutRightMargin这四个属性用于调整布局边框与内部组件之间的上、下、左、右的边距大小。

在设计窗体的上方有一个工具栏,用于使界面进入不同的设计状态,以及进行布局设计,工具栏商各按钮的功能如下:

按钮及快捷键 功能
Edit Widget(F3) 界面设计进入编辑状态,也就是正常的设计状态
Edit Signals/Slots(F4) 进入信号与槽的可视化设计状态
Edit Buddies 进入伙伴关系编辑状态,可以设置一个Lable与一个组件成为伙伴关系
Edit Tab Order 进入Tab顺序编辑状态,Tab顺序是指在键盘上按Tab键时,输入焦点在界面各组件之间跳动的顺序

3. 组件的信号与内建槽函数的关联

Qt的界面组件都是从QWidget继承而来的,都支持信号与槽的功能。每个类都有一些内建的信号和槽函数。例如QPushButton按钮类常用的信号是clicked(),在按钮被单击时发射此信号。QDialog是对话框类,它有以下3个内建的槽函数。

  • accept():功能是关闭对话框,表示肯定的选择,例如“确定”。
  • reject():功能是关闭对话框,表示否定的选择,例如“取消”。
  • close():功能是关闭对话框

这3个槽函数都可以关闭对话框,但是表示对话框的返回值不同,我们希望将“确定”按钮与对话框的accept()槽函数关联,将“退出”按钮与对话框的close()槽函数关联。

可以在Qt Designer里使用可视化的方式实现信号与槽函数的关联。在Qt Designer里单击上方工具栏里的“Edit Signals/Slots”按钮,窗体进入信号与槽函数编辑状态。

鼠标点选“确定”按钮,在按住鼠标左键拖动到窗体的空白区域后释放左键,这时出现关联设置对话框

此对话框里左边的列表框里显示了btnOK的信号(上图显示的是btnClear,因为btnOK之前自己已经关联过,就不重复关联了),选择clicked(),右边的列表框里显示了Dialog的槽函数,选择accept(),然后单击“OK”按钮。同样的方法可以将btnClose的clicked()信号与Dialog的close()槽函数关联,值得注意的是,如果没有看到close()槽函数,可以将下方的“Show signals and slots inherited from QWidget”打勾。

设置好这两个按钮的信号与槽关联后,在窗体右下方的Signals Slots编辑器里就显示了这两个关联。实际上可以直接在Signals Slots编辑器进行某个组件的内建信号与其他组件的内建槽函数关联。

4. 将ui文件转换为py

Dialog.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'Dialog.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 300)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        self.groupBox = QtWidgets.QGroupBox(Dialog)
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.chkBoxUnder = QtWidgets.QCheckBox(self.groupBox)
        self.chkBoxUnder.setObjectName("chkBoxUnder")
        self.horizontalLayout_3.addWidget(self.chkBoxUnder)
        self.chkBoxItalic = QtWidgets.QCheckBox(self.groupBox)
        self.chkBoxItalic.setObjectName("chkBoxItalic")
        self.horizontalLayout_3.addWidget(self.chkBoxItalic)
        self.chkBoxBold = QtWidgets.QCheckBox(self.groupBox)
        self.chkBoxBold.setObjectName("chkBoxBold")
        self.horizontalLayout_3.addWidget(self.chkBoxBold)
        self.verticalLayout.addWidget(self.groupBox)
        self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
        self.groupBox_2.setTitle("")
        self.groupBox_2.setObjectName("groupBox_2")
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.groupBox_2)
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.radioBlack = QtWidgets.QRadioButton(self.groupBox_2)
        self.radioBlack.setObjectName("radioBlack")
        self.horizontalLayout_4.addWidget(self.radioBlack)
        self.radioRed = QtWidgets.QRadioButton(self.groupBox_2)
        self.radioRed.setObjectName("radioRed")
        self.horizontalLayout_4.addWidget(self.radioRed)
        self.radioBlue = QtWidgets.QRadioButton(self.groupBox_2)
        self.radioBlue.setObjectName("radioBlue")
        self.horizontalLayout_4.addWidget(self.radioBlue)
        self.verticalLayout.addWidget(self.groupBox_2)
        self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.plainTextEdit.setFont(font)
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.verticalLayout.addWidget(self.plainTextEdit)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem)
        self.btnClear = QtWidgets.QPushButton(Dialog)
        self.btnClear.setObjectName("btnClear")
        self.horizontalLayout_2.addWidget(self.btnClear)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.btnOK = QtWidgets.QPushButton(Dialog)
        self.btnOK.setObjectName("btnOK")
        self.horizontalLayout_2.addWidget(self.btnOK)
        self.btnClose = QtWidgets.QPushButton(Dialog)
        self.btnClose.setObjectName("btnClose")
        self.horizontalLayout_2.addWidget(self.btnClose)
        self.verticalLayout.addLayout(self.horizontalLayout_2)

        self.retranslateUi(Dialog)
        self.btnOK.clicked.connect(Dialog.accept)
        self.btnClose.clicked.connect(Dialog.close)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Demo2-3信号与槽"))
        self.chkBoxUnder.setText(_translate("Dialog", "Underline"))
        self.chkBoxItalic.setText(_translate("Dialog", "Italic"))
        self.chkBoxBold.setText(_translate("Dialog", "Bold"))
        self.radioBlack.setText(_translate("Dialog", "Black"))
        self.radioRed.setText(_translate("Dialog", "Red"))
        self.radioBlue.setText(_translate("Dialog", "Blue"))
        self.plainTextEdit.setPlainText(_translate("Dialog", "PyQt5 编程指南
"
"Python 和 Qt."))
        self.btnClear.setText(_translate("Dialog", "清空"))
        self.btnOK.setText(_translate("Dialog", "确定"))
        self.btnClose.setText(_translate("Dialog", "退出"))
View Code

5. 窗体业务逻辑类文件myDialog.py

# # 与UI窗体类对应的业务逻辑类
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from Dialog import Ui_Dialog


class QmyDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建QWidget窗体
        self.ui = Ui_Dialog()  # 创建UI对象
        self.ui.setupUi(self)  # 构造UI


if __name__ == "__main__":
    app = QApplication(sys.argv)  # 创建app,用QApplication类
    form = QmyDialog()
    form.show()
    sys.exit(app.exec_())
View Code

6. 应用程序主程序文件appMain.py

# # GUI应用程序主程序
import sys
from PyQt5.QtWidgets import QApplication
from myDialog import QmyDialog

app = QApplication(sys.argv)  # 创建GUI应用程序
mainform = QmyDialog()  # 创建主窗体
mainform.show()  # 显示主窗体
sys.exit(app.exec_())
View Code

notes: 程序myDialog.py可以当做主程序直接运行,但是建议单独编写一个主程序文件appMain.py,appMain.py的功能是创建应用程序和主窗体,然后显示主窗体,并开始运行应用程序。它将myDialog.py文件的测试运行部分单独拿出来作为一个文件。当一个应用程序有多个窗体,并且窗体之间有数据传递时,appMain.py负责创建应用程序的主窗体并运行起来,这样使整个应用程序的结构更清晰。

原文地址:https://www.cnblogs.com/smart-zihan/p/12642624.html