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

Posted 肆拾伍

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python Qt GUI设计入门自建信号与槽函数关联相关的知识,希望对你有一定的参考价值。


前言

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

  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')
# 需要注意的是,这里都需要手动关联,并且槽函数是不能重名的,即使发送信号是同一个信号
# 还是仔细体会代码吧

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

总结

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

以上是关于Python Qt GUI设计入门自建信号与槽函数关联的主要内容,如果未能解决你的问题,请参考以下文章

Python Qt GUI设计:信号与槽的使用方法(基础篇—7)

Python Qt GUI设计:多线程中信号与槽的使用(基础篇—9)

C++ GUI Qt的建立连接,信号和槽

QT开发(十三)——QT信号与槽机制

QObject三大核心功能——信号与槽

qt1.3可视化界面和信号与槽