Python Qt GUI设计入门(四)自建信号与槽函数关联

Python GUI设计与数据可视化 Qt 同时被 2 个专栏收录
5 篇文章 1 订阅
17 篇文章 0 订阅


前言

信号与槽函数有以下几个特点:

  1. 一个信号可以关联多个槽函数。
  2. 一个信号可以关联其他信号。
  3. 信号的参数可以是任何Python数据类型。
  4. 一个槽函数可以和多个信号关联。
  5. 关联可以是同步也可以是异步的。
  6. 可以在不同线程之间建立关联。

上一章讲了一般内置信号和内置槽函数的关联使用,本章将介绍一些特殊情况以及,自定义信号和槽函数的使用。

一、重载overload信号的关联

名称相同但是参数个数或者类型不同的信号称为重载overload信号,这里我们可以看到之前选择信号时的图片:
在这里插入图片描述
这两个clicked信号的触发条件都一样,但是一个有返回参数,即如果使用clicked(bool),关联的槽函数会得到一个bool类型的输入参数。那么,这两个信号应该怎么使用呢?我们以上一章的代码为例:

如果我们采用的是不带参数的clicked方法,那么通过下面这条语句可以实现自动关联符合命名规则的槽函数。

 QtCore.QMetaObject.connectSlotsByName(Dialog)
     def on_pushButton_3_clicked(self): 
  		   self.ui.plainTextEdit.clear()

如果我们采用的是clicked(bool)信号,即便我们的槽函数命名符合规则,也不会自动关联,反而可能抛出异常退出程序。因为当出现具有相同名称的信号时,默认关联的是不带参数的信号,而槽函数定义的时候指定了输入参数,会导致输入参数不够而出错。

 QtCore.QMetaObject.connectSlotsByName(Dialog)
     def on_pushButton_3_clicked(self,checked): 
     	   print(checked)
  		   self.ui.plainTextEdit.clear()

上述代码应该修改为:

    @pyqtSlot(bool)  # 修饰器  告诉python 信号有boo类型输入参数l
    def on_checkBox_clicked(self,checked):
        print(checked)

不过要记得引入相关的库:

from PyQt5.QtCore import Qt,pyqtSlot

完整代码:

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

# Form implementation generated from reading ui file 'dialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.

# 文件保存为Proj2_dialog.py
from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(360, 240)
        self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog)
        self.plainTextEdit.setGeometry(QtCore.QRect(9, 59, 281, 138))
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.plainTextEdit.setFont(font)
        self.plainTextEdit.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.plainTextEdit.setCenterOnScroll(False)
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.horizontalLayoutWidget = QtWidgets.QWidget(Dialog)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(100, 30, 240, 21))
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.radioButton_3 = QtWidgets.QRadioButton(self.horizontalLayoutWidget)
        self.radioButton_3.setObjectName("radioButton_3")
        self.horizontalLayout.addWidget(self.radioButton_3)
        self.radioButton_2 = QtWidgets.QRadioButton(self.horizontalLayoutWidget)
        self.radioButton_2.setObjectName("radioButton_2")
        self.horizontalLayout.addWidget(self.radioButton_2)
        self.radioButton = QtWidgets.QRadioButton(self.horizontalLayoutWidget)
        self.radioButton.setObjectName("radioButton")
        self.horizontalLayout.addWidget(self.radioButton)
        self.horizontalLayoutWidget_3 = QtWidgets.QWidget(Dialog)
        self.horizontalLayoutWidget_3.setGeometry(QtCore.QRect(9, 203, 311, 30))
        self.horizontalLayoutWidget_3.setObjectName("horizontalLayoutWidget_3")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_3)
        self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_3.setSpacing(30)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.pushButton_3 = QtWidgets.QPushButton(self.horizontalLayoutWidget_3)
        self.pushButton_3.setObjectName("pushButton_3")
        self.horizontalLayout_3.addWidget(self.pushButton_3)
        self.pushButton_2 = QtWidgets.QPushButton(self.horizontalLayoutWidget_3)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_3.addWidget(self.pushButton_2)
        self.pushButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_3)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_3.addWidget(self.pushButton)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(20, 10, 81, 20))
        self.label.setObjectName("label")
        self.horizontalLayoutWidget_2 = QtWidgets.QWidget(Dialog)
        self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(100, 10, 240, 21))
        self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.checkBox_3 = QtWidgets.QCheckBox(self.horizontalLayoutWidget_2)
        self.checkBox_3.setObjectName("checkBox_3")
        self.horizontalLayout_2.addWidget(self.checkBox_3)
        self.checkBox_2 = QtWidgets.QCheckBox(self.horizontalLayoutWidget_2)
        self.checkBox_2.setObjectName("checkBox_2")
        self.horizontalLayout_2.addWidget(self.checkBox_2)
        self.checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget_2)
        self.checkBox.setObjectName("checkBox")
        self.horizontalLayout_2.addWidget(self.checkBox)
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(20, 30, 81, 16))
        self.label_2.setObjectName("label_2")

        self.retranslateUi(Dialog)
        self.pushButton_2.clicked.connect(Dialog.accept)
        self.pushButton.clicked.connect(Dialog.close)
        # self.checkBox.clicked[bool].connect(Dialog.checkBox_clicked)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.plainTextEdit.setPlainText(_translate("Dialog", "Hello World!"))
        self.radioButton_3.setText(_translate("Dialog", "Black    "))
        self.radioButton_2.setText(_translate("Dialog", "Red   "))
        self.radioButton.setText(_translate("Dialog", "Blue"))
        self.pushButton_3.setText(_translate("Dialog", "清空"))
        self.pushButton_2.setText(_translate("Dialog", "确认"))
        self.pushButton.setText(_translate("Dialog", "取消"))
        self.label.setText(_translate("Dialog", "字体样式"))
        self.checkBox_3.setText(_translate("Dialog", "Underline"))
        self.checkBox_2.setText(_translate("Dialog", "Italic"))
        self.checkBox.setText(_translate("Dialog", "Bold"))
        self.label_2.setText(_translate("Dialog", "字体颜色"))

# 新建另一个py文件,名字随意
import sys
from PyQt5.QtWidgets import QDialog,QApplication
from Proj2_dialog import Ui_Dialog
from PyQt5.QtCore import Qt,pyqtSlot

class QmyDialog(QDialog):
    def __init__(self):
        super().__init__()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
    def on_pushButton_3_clicked(self):
        self.ui.plainTextEdit.clear()
    def on_checkBox_3_toggled(self,checked):
        font = self.ui.plainTextEdit.font()
        # print(type(font))
        font.setUnderline(checked)
        self.ui.plainTextEdit.setFont(font)
    def on_checkBox_2_toggled(self,checked):
        font = self.ui.plainTextEdit.font()
        # print(type(font))
        font.setItalic(checked)
        self.ui.plainTextEdit.setFont(font)
    def on_checkBox_toggled(self,checked):
        font = self.ui.plainTextEdit.font()
        # print(type(font))
        font.setBold(checked)
        self.ui.plainTextEdit.setFont(font)

    @pyqtSlot(bool)
    def on_checkBox_clicked(self,checked):
        print(checked)



if __name__ =="__main__":
    app = QApplication(sys.argv)
    mydialog = QmyDialog()
    mydialog.show()
    sys.exit(app.exec_())

运行结果:
在这里插入图片描述

二、自定义信号

自定义信号分为无输入参数,单个输入参数,多个输入参数以及同名但是输入参数类型可变的重载overload信号。

自建信号必须是QObject的子类的属性,PyQt5.QtCore.pyqtSignal()能够为类建立信号。
代码如下(示例):

import sys
from PyQt5.QtCore import QObject,pyqtSlot,pyqtSignal

class Human(QObject): # 继承QObject,也可以是QObject的子类,比如说QWidget
    onePar_overload = pyqtSignal([int],[str])# 单个输入变量,int类型或者str类型
    twoPar_overload = pyqtSignal([int,int],[int,str])# 两个输入变量
    def onePar(self,int):
        print('onepar')
    def onePar_str(self,str1):
        print('onepar_str')
    def twopar(self,int1,int2):
        print(int1,int2)
    def twopar_str(self,int1,str2):
        print(int1,str2)

a = Human()
a.onePar_overload.connect(a.onePar)
a.onePar_overload.emit(1)# 发出信号,默认参数类型是第一个,也就是[int]
a.onePar_overload[str].connect(a.onePar_str)
a.onePar_overload[str].emit("123")# 发出信号,要指定发送信号类型是[str]
a.twoPar_overload.connect(a.twopar)
a.twoPar_overload.emit(1,2)
a.twoPar_overload[int,str].connect(a.twopar_str)
a.twoPar_overload[int,str].emit(1,'132')
# 需要注意的是,这里都需要手动关联,并且槽函数是不能重名的,即使发送信号是同一个信号
# 还是仔细体会代码吧

效果:
在这里插入图片描述

总结

我无数次希望把文章写得面面俱到,每个注意的小点都写清楚,但是我做不到,怪我太懒。文章啰里啰嗦就很烦,真的很佩服那些写教程写得清晰易懂的人,有问题还是留言问吧。

  • 0
    点赞
  • 2
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
初 级 篇 \第1章 Qt初步实践 2 \1.1 第一个Qt程序 2 \1.1.1 建立主程序 2 \1.1.2 建立工程 3 \1.1.3 编译/运行第一个Qt应用程序 8 \1.1.4 第一个Qt程序的代码分析 8 \1.2 使用Qt布局管理器 11 \1.3 关联操作 12 \1.4 小结 13 \第2章 对话框——QDialog 14 \2.1 自定义对话框 14 \2.1.1 建立新类 14 \2.1.2 添加子窗口部件 15 \2.2 加入主程序 22 \2.3 Qt内建(built-in)对话框 24 \2.4 小结 34 \第3章 基础窗口部件——QWidget 35 \3.1 Qt设计器绘制窗口部件 35 \3.1.1 Qt设计器基础 35 \3.1.2 绘制窗口部件 40 \3.2 程序中引入自定义窗口部件 47 \3.2.1 直接使用方式 47 \3.2.2 单一继承方式 49 \3.2.3 多继承方式 51 \3.3 Qt信号机制 53 \3.3.1 基本原理 53 \3.3.2 设计信号 55 \3.3.3 信号的自动关联 62 \3.4 窗口标志及几何布局 63 \3.4.1窗口标志 64 \3.4.2窗口部件的几何布局 66 \ \3.5 Qt样式表 74 \3.5.1 样式表语法 74 \3.5.2 样式表的应用 76 \3.6 Qt对象模型 79 \3.6.1 元对象系统 79 \3.6.2 属性系统 80 \3.6.3 对象树 83 \3.7 小结 86 \第4章 程序主窗口——QMainWindow 87 \4.1 QMainWindow主窗口框架 87 \4.2 Qt设计器绘制主窗口 88 \4.2.1 菜单 90 \4.2.2 工具栏 93 \4.2.3 中心部件 96 \4.3 代码创建主窗口 98 \4.3.1 创建资源文件 98 \4.3.2 定义主窗口类 98 \4.4 锚接部件 102 \4.5 状态栏 105 \4.6 实现文本编辑器功能 107 \4.7 多文档 118 \4.8 打印文档 119 \4.9 小结 120 \第5章 布局管理 121 \5.1 Qt布局管理器——QLayout 121 \5.1.1 Qt布局管理器简介 121 \5.1.2 布局管理器及窗口部件大小策略 \5.1.2 的应用 125 \5.2 分裂器部件QSplitter 132 \5.3 栈部件QStackedWidget 134 \5.4 工作空间部件QWorkspace 135 \5.5 多文档区部件QMdiArea 148 \5.6 小结 150 \ \中 级 篇 \第6章 2D绘图 152 \6.1 Arthur绘图基础 152 \6.1.1 绘图 152 \6.1.2 绘图设备 174 \6.2 坐标系统与坐标变换 175 \6.2.1 坐标系统 175 \6.2.2 坐标变换 175 \6.3 用不同的字体 177 \6.4 绘图路径——QPainterPath 180 \6.5 QImage与QPixmap绘图设备 182 \6.5.1 QImage 182 \6.5.2 Pixmap 183 \6.6 组合模式绘图 192 \6.7 Graphics View框架 200 \6.7.1 Graphics View体系结构 200 \6.7.2 Graphics View坐标系统 201 \6.7.3 深入Graphics View 202 \6.8 图形图像打印 208 \6.8.1 普通打印过程 208 \6.8.2 特殊窗口部件的打印 210 \6.9 小结 211 \第7章 拖放操作和剪贴板 212 \7.1 拖放操作 212 \7.1.1 拖放操作 212 \7.1.2 定义新的拖放操作类型 214 \7.1.3 Graphics View框架下的拖放 \7.1.3 操作 215 \7.2 使用剪贴板 217 \7.3 小结 218 \第8章 文件处理 219 \8.1 读写文本文件 219 \8.2 操作二进制文件 220 \8.3 临时文件 222 \8.4 目录操作和文件管理 222 \8.4.1 目录操作 222 \8.4.2 文件管理 224 \8.5 监视文件系统变化 225 \8.6 文件引擎 226 \8.7 小结 226 \第9章 网络 227 \9.1 FTP客户端 227 \9.2 HTTP客户端 235 \9.3 UDP应用 239 \9.4 TCP应用 243 \9.5 高级应用 253 \9.5.1 底层操作 253 \9.5.2 使用代理 256 \9.5.3 扩展Qt网络功能 256 \9.5.4 效率问题 260 \9
相关推荐
©️2020 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页

打赏

肆拾伍

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值