CH1.Qt概述
1.1 什么是Qt
1.1.1 定义
- 跨平台C++图形用户界面程序开发框架
- 用于开发GUI程序,也可以开发非GUI程序
1.1.2 Qt的优点
- 具有丰富的API.具有250多种以上的C++类
- 优良的跨平台性.支持多平台使用.
- 面向对象.具有良好的封装性,模块化清晰,使用signals/slots(信号/槽)来代替callback,具有更高的安全性.
1.2 Qt开发步骤及实例
1.2.1 采用Qt Designer实现计算圆面积
1. 界面设计
- 单击运行Qt Creator,进入欢迎界面,单击+New Project按钮创建一个新的项目
- 单击选择项目"Appaction"->"Qt Widgets Application"选项,单击"Choose…"按钮
- 保存路径按个人习惯命名,但是这里命名为Dialog
- 弹出Kit Selection(选择构建套件)界面,进入下一步即可
- 在类信息界面,根据实际需要选择基类,默认选择"创建界面"复选框,表示采用自带的界面设计器来设计界面.
- 单击完成,一系列的文件自动加载到项目文件中
- 双击dialog.ui,进入设计界面编辑状态,进行设计器编程
2. 编写相应的计算圆面积代码
方式1 : 在"Line Edit"文本框内输入半径值,然后单击"计算"按钮,在areaLabel_2中显示对应圆面积.编写代码步骤如下:
- 在"计算"按钮上单击鼠标右键,在弹出的下拉菜单中选择"转到槽…"命令,在对话框中选择clicked()信号,单击OK.如下图.
2. 进入dialog.cpp文件中按钮单击事件的槽函数0n_countBtn_clicked().在此函数中添加如下代码:
void Dialog:: on_countBtn_clicked()
{
bool ok;
QString tempStr;
QString valueStr=ui->radiusLineEdit->text();
int valueInt=valueStr.toInt(&ok);
double area=valueInt*valueInt*PI; //计算圆面积
ui->areaLabel_2->setText(tempStr.setNum(area));
- 在此文件开始出添加一下语句:
const static double PI = 3.1416;//定义全局变量PI
方式2 : 在"LIne Edit" 文本框内输入半径值,不需要单击按钮触发单击事件,直接在areaLabel_2中显示圆面积.编写代码步骤如下.
- 在"Line Edit"文本框上单击鼠标键,在弹出的下拉菜单中选择"转到槽…"命令,在"转到槽…"对话框中选择"textChanged(QString)"信号,如下图
- 单击“OK”按钮,进入dialog.cpp文件中的文本编辑框改变值内容事件的槽函数on_radiusLineEdit_textChanged(const QString &arg1)。在此函数中添加如下代码:
void Dialog::on_radiusLineEdit_textChanged(const QString &arg1)
{
bool ok;
QString tempStr;
QString valueStr=ui->radiusLineEdit->text();
int valueInt=valueStr.toInt(&ok);
double area=valueInt*valueInt*PI; //计算圆面积
ui->areaLabel_2->setText(tempStr.setNum(area));
}
运行此程序,在“Line Edit”文本框中输入半径值后,直接在areaLabel_2中显示圆的面积值,完成计算圆面积的功能。
运行结果
1.2.2 编写代码实现计算圆面积
- 创建新工程.创建过程和第一种方法步骤相同,只是项目命名为Dialog且保存路径D:\Qt\CH1\CH102,在类信息界面中取消“创建界面”复选框的选中状态。
- 在上述工程的dialog.h中添加注释以下的代码:
cpp
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
//插入以下代码
private:
QLabel *label1,*label2;
QLineEdit *lineEdit;
QPushButton *button;
};
此时要在文件首部加入头文件:
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
其中,Q_OBJECT宏的作用是启动Qt 5元对象系统的一些特性(如支持信号和槽等),它必须放置到类定义的私有区中。
3. 在dialog.cpp 中添加如下代码:
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
label1=new QLabel(this);
label1->setText(tr("请输入圆的半径:"));
lineEdit=new QLineEdit(this);
label2=new QLabel(this);
button=new QPushButton(this);
button->setText(tr("显示对应圆的面积"));
QGridLayout *mainLayout=new QGridLayout(this);
mainLayout->addWidget(label1,0,0);
mainLayout->addWidget(lineEdit,0,1);
mainLayout->addWidget(label2,1,0);
mainLayout->addWidget(button,1,1);
}
其中,QGridLayout *mainLayout=new QGridLayout(this)用于布局管理器,将所有控件的位置固定。
4. 在此文件一开始添加头文件:
#include <QGridLayout>
运行结果
方式1: 在lineEdit文本框内输入所需圆的半径值,单击“显示对应圆的面积”按钮后,在label2中显示相对应的圆的面积值。
5. 打开dialog.h文件,在类构造函数和控件成员声明后,添加如下加黑代码:
class Dialog : public QDialog
{
... ...
QPushButton *button;
private slots:
void showArea();
};
- 打开dialog.cpp文件,在构造函数中添加如下加黑代码:
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
... ...
mainLayout->addWidget(button,1,1);
connect(button,SIGNAL(clicked()),this,SLOT(showArea()));
}
- 在showArea()中实现显示圆面积功能,代码如下:
void Dialog::showArea()
{
bool ok;
QString tempStr;
QString valueStr=lineEdit->text();
int valueInt=valueStr.toInt(&ok);
double area=valueInt*valueInt*PI;
label2->setText(tempStr.setNum(area));
}
- 在此文件开始处添加全局变量:
const static double PI=3.1416;
- 运行,输入半径值,点击"显示对应圆的面积"按钮,显示结果;
1.3 Qt5 安装: 概念解析
1.3.1 信号和槽机制(Signal&Slot)
1. 信号与槽机制的连接方式
(1)一个信号可以与另一个信号相连,代码如下:
connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal1));
(2)同一个信号可以与多个槽相连,代码如下:
connect(Object1,SIGNAL(signal2),Object2,SIGNAL(slot2));
connect(Object1,SIGNAL(signal2),Object3,SIGNAL(slot1));
(3)同一个槽可以响应多个信号,代码如下:
connect(Object1,SIGNAL(signal2),Object2,SIGNAL(slot2));
connect(Object3,SIGNAL(signal2),Object2,SIGNAL(slot2));
但是,常用的连接方式为:
connect(Object1,SIGNAL(signal),Object2,SLOT(slot));
2.信号与槽机制的优点
(1)类型安全。需要关联的信号和槽的签名必须是等同的,即信号的参数类型和参数个数与接收该信号的槽的参数类型和参数个数相同。不过,一个槽的参数个数是可以少于信号的参数个数的,但缺少的参数必须是信号参数的最后一个或几个参数。
(2)松散耦合。信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无须知道是哪个对象的哪个槽需要接收它发出的信号,它只需做的是在适当的时间发送适当的信号就可以了,而不需要知道也不关心它的信号有没有被接收到,更不需要知道是哪个对象的哪个槽接收到了信号。
3.信号与槽机制的效率
信号和槽机制增强了对象间通信的灵活性,然而这也损失了一些性能。同回调函数相比,信号和槽机制运行速度有些慢。通常,通过传递一个信号来调用槽函数将会比直接调用非虚函数运行速度慢10倍。原因主要如下。
(1)需要定位接收信号的对象。
(2)安全地遍历所有的关联(如一个信号关联多个槽的情况)。
(3)编组(marshal)/解组(unmarshal)传递的参数。
(4)多线程的时候,信号可能需要排队等待。
4. Qt 5元对象系统基于以下三个事实
(1)基类QObject:任何需要使用元对象系统功能的类必须继承自QObject。
(2)Q_OBJECT宏:Q_OBJECT宏必须出现在类的私有声明区,用于启动元对象的特性。
(3)元对象编译器(Meta-Object Compiler,moc):为QObject子类实现元对象特性提供必要的代码实现。
5. 布局管理器
在设计较复杂的GUI用户界面时,仅通过指定窗口部件的父子关系以期达到加载和排列窗口部件的方法是行不通的,最好的办法是使用Qt提供的布局管理器。
QGridLayout *mainLayout=new QGridLayout(this); //(a)
mainLayout->addWidget(label1,0,0); //(b)
mainLayout->addWidget(lineEdit,0,1);
mainLayout->addWidget(label2,1,0);
mainLayout->addWidget(button,1,1);
setLayout(mainLayout); //(c)