前言
在上一节,通过一个简单的应用程序,分析了Qt创建的GUI应用程序中各个文件的作用,剖析了可视化设计的UI文件是如何被转换为C++的类定义,并自动创建界面的。这些是使用QtCreator可视化设计用户界面,并使各个部分融合起来运行的基本原理。本节再以一个稍微复杂的例子来讲解设计GUI的常见功能,包括界面设计时布局的管理,程序里如何访问界面组件,以及Qt关键的信号与槽的概念。
一、界面总体布局
如此新建的项目sample2有一个界面文件qwdialog.ui,一-个头文件qwdialog.h和源程序文件qwdialog.cpp。此外,还
有项目文件sample2.pro 和主程序文件main.cpp。
qwdialog.ui界面文件设计时界面如图2-6所示。程序的主要功能是对中间一个文本框的文字字体样式和颜色进行设置。
在界面设计时,对需要访问的组件修改其objectName,如各个按钮、需要读取输入的编辑框、需要显示结果的标签等,
以便于在程序中进行区分。对于不需要程序访问的组件则无需修改其objectName,如用于界面上组件分组的GroupBox、
Frame、 布局等,让UI设计器自动命名即可。
Layouts和Spacers两个组件面板里的布局组件的功能见下表。
布局组件 | 功能 |
---|---|
Vertical Layout | 垂直方向布局,组件自动在垂直方向上分布 |
Horizontal Layout | 水平方向布局,组件自动在水平方向.上分布 |
Grid Layout | 网格状布局,网状布局大小改变时,每个网格的大小都改变 |
Form Layout | 窗体布局,与网格状布局类似,但是只有最右侧的一-列网格会改变大小 |
Horizontal Spacert | 一个用于水平分隔的空格 |
Vertical Spacer | 一个用 于垂直分隔的空格 |
使用组件面板里的布局组件设计布局时,先拖放–个布局组件到窗体上,如在设计上图3个按钮的布局时,先放- -个
Horizontal Layout 到窗体上,布局组件会以红色边框显示。再往布局组件里拖放3个Push Button和2个Horizontal
Spacer, 就可以得到上图3个按钮的水平布局效果。
二、信号与槽
信号与槽(Signal & Slot)是Qt编程的基础,也是Qt的一大创新。因为有了信号与槽的编程机制,在Qt中处理界面各个组件的交互操作时变得更加直观和简单。
1、信号
信号(Signal) 就是在特定情况下被发射的事件,例如PushButton 最常见的信号就是鼠标单击时发射的clicked0信号,一
个ComboBox最常见的信号是选择的列表项变化时发射的CurrentIndexChanged(信号。GUI程序设计的主要内容就是对
界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就可以了。
2、槽
槽(Slot) 就是对信号响应的函数。槽就是一个函数,与一般的C++函数是一样的,可以定义在类的任何部分( public、
private 或protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号
关联,当信号被发射时,关联的槽函数被自动执行。
3、信号与槽具体实现
信号与槽关联是用QObject::connect)函数实现的,其基本格式是:
Qobject: : connect (sender, SIGNAL(signal()), receiver, SLOT (slot())) ;
connect()是QObject类的-一个静态函数,而QObject是所有Qt类的基类,在实际调用时可以忽略前面的限定符,所以可
以直接写为:
connect (sender, SIGNAL(signal()) ,receiver, SLOT(slot())) ; //sender:发射对象,signal():信号名称,receiver:接收对象,slot():槽,
其中,sender是发射信号的对象的名称,signal()是信号名称。
信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。receiver是接收信号的对象名称,slot()是槽函数
的名称,需要带括号,有参数时还需要指明参数。
SIGNAL和SLOT是Qt的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。
例如,在sample的ui_ widget.h 文件中,在setupUi( )函数中有如下的语句:
Qobject: :connect (btnClose,SIGNAL(clicked()), Widget, SLOT(close())) ;
其作用就是将btnClose按钮的clicked)信号与窗体( Widget)的槽函数close()相关联,这样,当单击btnClose按钮(就是界面
上的“Close”按钮)时,就会执行Widget 的close()槽函数。
关于信号与槽的使用,有以下一些规则需要注意。
(1)一个信号可以连接多个槽,例如:
connect (spinNum, SIGNAL (valueChanged(int)), this, SLOT (addFun(int)) ;
connect (spinNum, SIGNAL (valueChanged(int)),this, SLOT (updateStatus (int)) ;
当一个对象spinNum的数值发生变化时,所在窗体有两个槽进行响应,一 个addFun()用于计算,一个updateStatus()用
于更新状态。
当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。
当信号和槽函数带有参数时,在connect()函数里,要写明参数的类型,但可以不写参数名称。
(2)多个信号可以连接同一个槽,例如在本项目的设计中,让三个选择颜色的RadioButton的clicked()信号关联到相同的
一个 自定义槽函数setTextFontColor()。
connect (ui->rBtnBlue, SIGNAL(clicked()) , this, SLOT (setTextFontColor())) ;
connect (ui->rBtnRed, SIGNAL(clicked()) , this, SLOT (setTextFontColor())) ;
connect (ui->rBtnBlack, SIGNAL (clicked()) , this, SLOT (setTextFontColor())) ;
这样,当任何一个RadioButton被单击时,都会执行setTextFontColor()函数。
(3)一个信号可以连接另外一个信号。
例如: connect (spinNum,SIGNAL (valueChanged(int)),this, SIGNAL (refreshInfo(int)) ;
这样,当一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。
(4)严格的情况下,信号与槽的参数个数和类型需要- -致, 至少信号的参数不能少于槽的参数。如果不匹配,会出现编
译错误或运行错误。
(5)在使用信号与槽的类中,必须在类的定义中加入宏Q_OBJECT。
(6)当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一 样。只有当信号关联的所有槽
函数执行完毕后,才会执行发射信号处后面的代码。