GUI程序框架(C)|信号与槽功能概述

1.信号与槽功能概述

信号与槽的编程机制,在Qt中处理界面组件的交互操作时变得比较直观和简单

信号(Signal)就是在特定情况下被发射(emit)的一种通告

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

槽(Slot)就是对信号响应的函数

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

2.Qt Creator的使用

用Qt Creator内置的UI Designer可视化设计窗体,方便提取组件的信号并创建信号的槽函数原型

1.启动Qt Creator,创建一个名为QtApp的C++ GUI应用程序项目

GUI程序框架(C)|信号与槽功能概述插图

2.创建项目的名称设置为QtApp

GUI程序框架(C)|信号与槽功能概述插图1

3.我们这次不需要编译随便选一个编译器都行

4.创建UI窗体的设置,选择基类QDialog

GUI程序框架(C)|信号与槽功能概述插图2

5.Qt Creator的界面非常简洁,本书不需要用它来编写C++程序,而只是用于窗体可视化设计和槽函数原型生成,所以用到的功能较少。

GUI程序框架(C)|信号与槽功能概述插图3

窗体左侧是项目的文件管理目录树,与窗体相关的文件有以下3个。
· Dialog.ui是窗体UI文件,双击这个文件,会打开内置的UI Designer进行窗体可视化设计。
· Dialog.h和Dialog.cpp是定义窗体业务逻辑类的头文件和程序实现文件。


3.窗体可视化设计

双击文件Dialog.ui可以打开内置的UI Designer对窗体进行可视化设计

GUI程序框架(C)|信号与槽功能概述插图4

在界面可视化设计时,对于需要在窗体业务逻辑类里访问的界面组件,修改其objectName,例如各个按钮、需要读取输入的编辑框、需要显示结果的标签等,以便在程序里加以区分。对于不需要在程序里访问的界面组件则无须修改其objectName,例如用于界面上组件分组的GroupBox、Frame、布局等,UI Designer自动命名即可。

窗体的主要组件的命名、属性设置

GUI程序框架(C)|信号与槽功能概述插图5

(1)objectName是窗体上的组件的实例名称,界面上的每个组件需要有一个唯一的objectName,程序里访问界面组件时都通过其objectName进行访问,自动生成的槽函数名称与objectName有关。所以,组件的objectName需要在设计程序之前设置好,设置好之后一般不再改动。若程序设计好之后再改动objectName,涉及的代码需要进行相应的改动。
(2)窗体的objectName是窗体的类名称,也就是利用向导新建窗体时设置的名称,在UI Designer里一般不修改窗体的objectName。


4. 界面组件布局管理

Qt的窗体设计具有布局(layout)功能。所谓布局,就是界面上的组件的排列方式。使用布局管理功能可以使组件有规则地分布,并且随着窗体大小变化自动地调整大小和相对位置。布局管理是GUI设计的必备技巧

1.界面组件的层次关系

为了将界面上的各个组件的分布设计得更加美观,经常使用一些容器类组件,如GroupBox、TabWidget、Frame等。例如,将3个CheckBox(复选框)组件放置在一个GroupBox组件里,这个GroupBox组件就是这3个复选框的容器,移动这个GroupBox就会同时移动其中的3个CheckBox

在窗体上放置两个GroupBox组件

其中在groupBox1里放置3个CheckBox组件,在groupBox2里放置3个RadioButton按钮

GUI程序框架(C)|信号与槽功能概述插图6
2-16

2.布局管理

Qt为窗体设计提供了丰富的布局管理功能,在UI Designer里,组件面板里有Layouts和Spacers两个分组,在窗体上方的工具栏里有布局管理的按钮

GUI程序框架(C)|信号与槽功能概述插图7
2-17

组件面板里Layouts和Spacers这两个分组里的布局组件的功能如表所示

GUI程序框架(C)|信号与槽功能概述插图8

使用组件面板里的布局组件设计布局时,先拖放一个布局组件到窗体上,例如在设计图2-17窗体下方的3个按钮的布局时,先放一个Horizontal Layout到窗体上,布局组件会以红色矩形框显示。再向布局组件里拖放3个PushButton和两个Horizontal Spacer,就可以得到图2-17中3个按钮的水平布局效果。
每个布局还有layoutTopMargin、layoutBottomMargin、layoutLeftMargin、layoutRightMargin这4个属性用于调整布局边框与内部组件之间的上、下、左、右的边距大小。
在设计窗体的上方有一个工具栏,用于使界面进入不同的设计状态,以及进行布局设计,工具栏上各按钮的功能如表所示。

GUI程序框架(C)|信号与槽功能概述插图9

使用工具栏上的布局设计按钮时,只需在窗体上选中需要设计布局的组件,然后点击某个布局按钮即可。在窗体上选择组件时同时按住Ctrl键,可以实现组件多选。选择某个容器类组件,相当于选择了其内部的所有组件。例如,在图2-16的窗体中,选中groupBox1,然后单击“Lay Out Horizontally”工具栏按钮,就可以对groupBox1内的3个复选框水平布局。

在图2-16的窗体上,使groupBox1里的3个复选框水平布局,groupBox2里的3个RadioButton按钮水平布局,下方放置的3个按钮水平布局,窗体上又放置一个PlainTextEdit组件。现在如果改变groupBox1、groupBox2或按钮的水平布局的大小,其内部组件会自动改变大小,但是如果改变窗体大小,界面上的各组件却并不会自动改变大小
还需为窗体指定一个总的布局---选中窗体(即不选择任何组件),单击工具栏上的“Lay Out Vertically”按钮,使4个组件垂直分布。这样布局后,当窗体大小改变时,各个组件都会自动改变大小,且当窗体纵向增大时,只有中间的文本框增大,其他3个布局组件不增大。最终设计好的窗体的组件布局如图所示,从图中可以清楚地看出组件的层次关系,以及布局的设置

GUI程序框架(C)|信号与槽功能概述插图10
设计好的窗体的组件布局与层次关系

在窗体可视化设计布局时,要善于利用水平和垂直空格组件,善于设置组件的最大、最小宽度或高度属性,善于设置布局的layoutStretch等属性来达到布局效果。

3.伙伴关系与Tab顺序

在UI Designer工具栏上单击“Edit Buddies”按钮可以进入伙伴关系编辑状态

伙伴关系(Buddy)是指界面上一个Label和一个具有输入焦点的组件相关联,单击一个Label,按住鼠标左键,然后拖向一个组件,就建立了Label和组件之间的伙伴关系。

伙伴关系是为了在程序运行时,在窗体上用快捷键快速将输入焦点切换到某个组件上。

在UI Designer工具栏上单击“Edit Tab Order”按钮进入Tab顺序编辑状态

Tab顺序是指在程序运行时,按下键盘上的Tab键时输入焦点的移动顺序。一个好的用户界面,在按Tab键时焦点应该以合理的顺序在界面上移动。

GUI程序框架(C)|信号与槽功能概述插图11
Tab顺序编辑状态

进入Tab顺序编辑状态后,在界面上会显示具有Tab顺序的组件的Tab顺序编号,依次按希望的顺序单击组件,就可以重排Tab顺序了。没有输入焦点的组件是没有Tab顺序的,例如Label组件。


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

Qt的界面组件都是从QWidget继承而来的,都支持信号与槽的功能

每个类都有一些内建的信号和槽函数,例如QPushButton按钮类常用的信号是clicked(),在按钮被单击时发射此信号。QDialog是对话框类,它有以下3个内建的槽函数。
· accept(),功能是关闭对话框,表示肯定的选择,例如“确定”。
· reject(),功能是关闭对话框,表示否定的选择,例如“取消”。
· close(),功能是关闭对话框。

这3个槽函数都可以关闭对话框,但是表示的对话框的返回值不同

在UI Designer里单击上方工具栏里的“Edit Signals/Slots”按钮,窗体进入信号与槽函数编辑状态

GUI程序框架(C)|信号与槽功能概述插图12
窗体进入Signals/Slots编辑状态(已设置好关联)

鼠标点选“确定”按钮,再按住鼠标左键拖动到窗体的空白区域后释放左键,这时出现如图2-22所示的关联设置对话框。此对话框左边的列表框里显示了btnOK的信号,选择clicked(),右边的列表框里显示了Dialog的槽函数,选择accept(),然后单击“OK”按钮。同样的方法可以将btnClose的clicked()信号与Dialog的close()槽函数关联。

GUI程序框架(C)|信号与槽功能概述插图13

6. PyQt5 GUI项目程序框架

1. 项目文件组成

在完成上一步的窗体可视化设计后,就可以将窗体文件Dialog.ui编译转换为相应的Python类定义文件,并编写PyQt5 GUI应用程序,测试程序运行效果

GUI程序框架(C)|信号与槽功能概述插图14

2.批处理文件uic.bat

新建文件uic.bat,内容如下:

echo off
rem将子目录QtApp下的.ui文件复制到当前目录下
copy .\QtApp\Dialog.ui Dialog.ui
rem用pyuic5编译.ui文件
pyuic5 -o ui_Dialog.py  Dialog.ui

uic.bat文件是指令批处理文件,运行批处理文件就相当于在Windows的cmd窗口里顺序执行文件里的操作指令。

  • 文件中的rem表示注释行
  • 第一条是复制Dialog.ui命令
  • 第二条是将Dialog.ui编译为py程序文件ui_Dialog.py命令
  • 双击执行

3.窗体界面定义文件ui_Dialog.py

运行批处理文件uic.bat后,将得到窗体UI文件Dialog.ui编译后的窗体界面定义文件ui_Dialog.py

GUI程序框架(C)|信号与槽功能概述插图15

信号与槽函数关联使用connect()函数,语句如下:

sender.signalName.connect(receiver.slotName)

其中:
· sender表示发射信号的对象名称,如self.btnOK;
· signalName表示信号的名称,如clicked;
· receiver是对信号作出响应的接收者的名称,如Dialog;
· slotName是接收者的响应槽函数的名称,如accept。
所以,对于在Signals Slots编辑器里可视化设置的关联,setupUi()函数将自动生成信号与槽关联的语句。

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

前文介绍的界面与业务逻辑分离且界面独立封装的方式定义一个类QmyDialog,并保存为文件myDialog.py。文件代码如下:

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


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


if  __name__ == "__main__":       #用于当前窗体测试
    app = QApplication(sys.argv)   #创建GUI应用程序
    form=QmyDialog()                #创建窗体
    form.show()
    sys.exit(app.exec_())

这个文件有窗体测试程序,运行此文件时,就会执行文件后面部分的程序,其功能是创建应用程序和窗体,并运行应用程序。
现在运行程序myDialog.py就会出现所设计的窗体,点击窗体上的“确定”和“退出”按钮可以关闭窗体并退出程序,说明这两个按钮的功能实现了。这是因为在QmyDialog类的构造函数中,创建了窗体类的实例对象self.ui,并调用了其setupUi()函数,即下面这两行语句:

self.ui=Ui_Dialog()       #创建UI对象
self.ui.setupUi(self)     #构造UI

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

程序myDialog.py可以当作主程序直接运行,但是建议单独编写一个主程序文件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_())

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

为了避免混淆,我们在命名文件时,将文件名与文件内的类名称区分开来,将Python中针对UI窗体创建的业务逻辑类的名称与UI窗体名称区分开来,这与Eric中的命名方法不同。

例如,UI文件Dialog.ui中的窗体名称是Dialog,文件Dialog.ui编译后生成的Python类名称是固定的Ui_Dialog,我们设置保存为文件ui_Dialog.py,而Eric会自动保存为文件Ui_Dialog.py。

针对文件ui_Dialog.py中的类Ui_Dialog创建的窗体业务逻辑类是可以自由命名的,我们将类命名为QmyDialog,保存为文件myDialog.py。而在Eric中创建的业务逻辑类默认的文件名是Dialog.py,类名称也是Dialog,这对于初学者容易造成混淆。

6.为组件的内建信号编写槽函数

1.自动关联的槽函数

为清空按钮编写槽函数

  • 打开.pro实例项目-》选中清空按钮-》鼠标右键-》“Go to slot”菜单项->选择clicked()信号->点击Ok

会在QtApp项目的Dialog.cpp文件里生成下面这样一个C++槽函数框架:

 void DialogText::on_btnClear_clicked()
 {
 }

按快捷键F4会在Dialog.h和Dialog.cpp文件之间切换,在Dialog.h文件里可看到自动生成的这个槽函数的C++原型定义:

void on_btnClear_clicked();

我们并不需要编写任何C++程序,而只需要自动生成的这个槽函数名称。复制此函数名称,在myDialog.py文件的QmyDialog类里定义一个同名的函数并编写代码:

def on_btnClear_clicked(self):
    self.ui.textEdit.clear()

现在若运行myDialog.py文件,会发现“清空”按钮可用了,它会将文本框里的内容全部清除。

同样,在UI Designer里可视化设计窗体时,选中“Bold”复选框,打开其Go to slot对话框,这里显示了QCheckBox类的所有信号。

GUI程序框架(C)|信号与槽功能概述插图16

其中的toggled(bool)信号在复选框的状态变化时发射,复选框的勾选状态作为参数传递给函数,点击“OK”按钮后生成其C++槽函数原型为:

    void on_chkBoxBold_toggled(bool checked);

在myDialog.py文件的QmyDialog类里定义一个同名函数,并且具有相同类型的参数,代码如下:

    def on_chkBoxBold_toggled(self, checked):
        font=self.ui.textEdit.font()
        font.setBold(checked)    #参数checked表示勾选状态
        self.ui.textEdit.setFont(font)

现在若运行myDialogText.py文件,会发现“Bold”复选框可用了,会使文本框的字体在粗体和正常之间切换。

同样,在窗体可视化设计时,选中“Underline”复选框,打开其Go to slot对话框如图2-26所示。在对话框里不选择toggled(bool)信号,而是选择clicked()信号。而且要注意,还有一个带参数的clicked(bool)信号,它会将点击复选框时的勾选状态当作一个参数传递给槽函数。现在暂时用clicked()信号,对于同名而参数不同的overload型信号的处理在后面讨论。
“Underline”复选框的clicked()信号的C++槽函数原型是:

void on_chkBoxUnder_clicked();

在myDialog.py文件的QmyDialog类里定义一个同名函数并编写代码。现在QmyDialog类的完整代码如下:

import sys
from PyQt5.QtWidgets import  QApplication, QDialog
from ui_Dialog import Ui_Dialog


class QmyDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)    #调用父类构造函数,创建窗体
        self.ui=Ui_Dialog()         #创建UI对象
        self.ui.setupUi(self)       #构造UI
    def on_btnClear_clicked(self):
        self.ui.plainTextEdit.clear()
##==== 由connectSlotsByName() 自动与组件的信号关联的槽函数=====

    def on_checkBoxBold_toggled(self, checked):
        ## "Bold" 复选框
        font=self.ui.plainTextEdit.font()
        font.setBold(checked)    #参数checked表示勾选状态
        self.ui.plainTextEdit.setFont(font)
    
    def on_checkBoxunder_clicked(self):           
        ## "Underline"复选框
        checked=self.ui.checkBoxunder.isChecked()  #读取勾选状态
        font=self.ui.plainTextEdit.font()
        font.setUnderline(checked)
        self.ui.plainTextEdit.setFont(font)

在QmyDialog类里定义了3个函数,这3个函数与相应界面组件的信号关联起来了,实现了信号与槽的关联。但是,在QmyDialog类的构造函数里并没有添加任何代码进行信号与槽的关联,而Ui_Dialog类也没有做任何修改(在UI Designer里可视化生成槽函数框架时,并不会对Dialog.ui做任何修改,所以无须重新编译Dialog.ui),这些信号与槽的关联是如何实现的呢?

秘密在于ui_Dialog.py文件中的Ui_Dialog.setupUi()函数的最后一行语句

QtCore.QMetaObject.connectSlotsByName(Dialog)

使用了Qt的元对象(QMetaObject),它会搜索Dialog窗体上的所有从属组件,将匹配的信号和槽函数关联起来,它假设槽函数的名称是:

on_<object name>_<signal name>(<signal parameters>)

在组件的Go to slot对话框里,选择一个信号后生成的槽函数名称就是符合这个命名规则的。所以,如果在UI Designer里通过可视化设计自动生成槽函数框架,然后复制函数名到Python程序里,这样的槽函数就可以和组件的信号自动关联,而不用逐个手工编写关联的语句。
不符合这样的命名规则的函数不能自动与信号关联,即使非常小的改动,例如函数on_btnClear_clicked()改为on_btnClear_clicked2(),也不能与组件的信号自动关联。

要在Qt Creator中通过Go to slot对话框为一个UI窗体上的组件自动生成槽函数框架,UI窗体文件必须是在一个Qt GUI项目里打开的,一个.ui文件有对应的.h和.cpp文件。像示例Demo2_2里那样只有一个独立的.ui文件是不能生成槽函数框架的。使用Qt的独立软件Qt Designer只能设计UI窗体,没有Go to slot对话框,不能生成槽函数框架,这就是为什么我们使用Qt Creator内置的UI Designer,而不使用独立的Qt Designer的原因。

2.overload型信号的处理

有两个名称为clicked的信号,一个是不带参数的clicked()信号,“Underline”复选框使用这个信号生成槽函数是可以自动关联的;另一个是带参数的clicked(bool)信号,它将复选框的当前勾选状态作为参数传递给槽函数。这种名称相同但参数个数或类型不同的信号就是overload型信号。
对于窗体上的“Italic”复选框,在其Go to slot对话框中选择clicked(bool)信号生成槽函数原型,用相应的函数名在QmyDialog类中定义一个函数,代码如下:

def on_chkBoxItalic_clicked(self, checked):
    font=self.ui.textEdit.font()
    font.setItalic(checked)
    self.ui.textEdit.setFont(font)

我们“以为”这个槽函数会和chkBoxItalic的clicked(bool)信号自动关联,运行文件myDialog.py,却发现点击“Italic”复选框时,程序出现异常直接退出了!为什么会出现这种情况呢?

因为有两个不同类型参数的clicked信号,connectSlotsByName()函数进行信号与槽函数的关联时会使用一个默认的信号,对QCheckBox来说,默认使用的是不带参数的clicked()信号。而现在定义的函数on_chkBoxItalic_clicked(self, checked)是需要传递进来一个参数的,程序运行到on_chkBoxItalic_clicked(self, checked)函数时,无法给它传递一个参数checked,所以发生了异常。
要解决这个问题,需要使用@pyqtSlot修饰符,用这个修饰符将函数的参数类型声明清楚。将on_chkBoxItalic_clicked()函数的代码修改为如下形式:

from PyQt5.QtCore import  Qt,pyqtSlot
--snip--
    @pyqtSlot(bool)     ##修饰符指定参数类型,用于overload型的信号
    def on_checkBoxItalic_clicked(self, checked):
        font=self.ui.plainTextEdit.font()
        font.setItalic(checked)
        self.ui.plainTextEdit.setFont(font)

这样使用@pyqtSlot修饰符声明函数参数类型后,connectSlotsByName()函数就会自动使用clicked(bool)信号与这个槽函数关联,运行就没有问题了。

对于非默认的overload型信号,槽函数必须使用修饰符@pyqtSlot声明函数参数类型

如果两种参数的overload型信号都要关联槽函数,那么两个槽函数名必须不同名,且在关联时要做设置

3.手动关联信号与槽函数

很多情况下也需要手工编写代码进行信号与槽的关联,如我们希望将设置颜色的3个RadioButton按钮的clicked()信号与同一个槽函数关联
在QmyDialog类里定义一个新的函数do_setTextColor(),并且在构造函数里进行关联,添加这些功能后的myDialog.py的完整代码如下:

##与UI窗体类对应的业务逻辑类
import sys
from PyQt5.QtWidgets import  QApplication, QDialog
from ui_Dialog import Ui_Dialog
from PyQt5.QtCore import  Qt,pyqtSlot
from PyQt5.QtGui import QPalette

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

    def on_btnClear_clicked(self):
        self.ui.plainTextEdit.clear()
##==== 由connectSlotsByName() 自动与组件的信号关联的槽函数=====

    def on_checkBoxBold_toggled(self, checked):
        ## "Bold" 复选框
        font=self.ui.plainTextEdit.font()
        font.setBold(checked)    #参数checked表示勾选状态
        self.ui.plainTextEdit.setFont(font)
    
    def on_checkBoxunder_clicked(self):           
        ## "Underline"复选框
        checked=self.ui.checkBoxunder.isChecked()  #读取勾选状态
        font=self.ui.plainTextEdit.font()
        font.setUnderline(checked)
        self.ui.plainTextEdit.setFont(font)
    
    @pyqtSlot(bool)     ##修饰符指定参数类型,用于overload型的信号
    def on_checkBoxItalic_clicked(self, checked):#"Italic"复选框
        font=self.ui.plainTextEdit.font()
        font.setItalic(checked)
        self.ui.plainTextEdit.setFont(font)
    ##=========自定义槽函数========
    def do_setTextColor(self): ##设置文本颜色
        plet = self.ui.plainTextEdit.palette() #获取palette
        if (self.ui.radioButtonBlack.isChecked()):
            plet.setColor(QPalette.Text,Qt.black)
    #black
        elif (self.ui.radioButtonBlue.isChecked()):
            plet.setColor(QPalette.Text,Qt.blue)
    #blue
        elif (self.ui.radioButtonRed.isChecked()):
            plet.setColor(QPalette.Text,Qt.red)
    #red
        self.ui.plainTextEdit.setPalette(plet)
    #设置palette

if  __name__ == "__main__":       #用于当前窗体测试
    app = QApplication(sys.argv)   #创建GUI应用程序
    form=QmyDialog()                #创建窗体
    form.show()
    sys.exit(app.exec_())

在QmyDialog的构造函数中增加了下面3条语句:

self.ui.radioBlack.clicked.connect(self.do_setTextColor)
self.ui.radioRed.clicked.connect(self.do_setTextColor)
self.ui.radioBlue.clicked.connect(self.do_setTextColor)

这样就将3个RadioButton按钮的clicked()信号与同一个槽函数do_setTextColor()关联起来了,实现了信号与槽函数的关联。

为了与connectSlotsByName()自动关联的槽函数区别,自定义槽函数的函数名一律使用“do_”作为前缀。当然,这只是个人习惯的命名规则

版权声明:
作者:RHZ
链接:https://www.rhzhz.cn/?p=601
来源:RHZ | 用文字记录工作和学习生活
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
GUI程序框架(C)|信号与槽功能概述
1.信号与槽功能概述 信号与槽的编程机制,在Qt中处理界面组件的交互操作时变得比较直观和简单 信号(Signal)就是在特定情况下被发射(emit)的一种通……
<<上一篇
下一篇>>