在《QT基础知识》中介绍了窗体设计界面的每个部分:
这里我们来细说一下每一部分的功能。
组件面板
组件面板上有着非常多的Qt组件,我们利用思维导图的形式,将Qt组件呈现出来:
Qt组件众多,上面的思维导图后的概要图只展示了四个部分的组件,其余部分要在具体的组合才能体现出来。
对象浏览器
在对象浏览器上用树状视图显示窗体上各组件之间的布局包含关系,视图有两列,显示每个组件的对象名称和类名称。
例如上图,我们先拖拽一个groupBox组合框,然后将label组件和Push Button组件拖拽进组合框内,在对象浏览器中可以看到groupBox组合框包含label组件和Push Button且三者的类分别为:QGroupBox、QLabel、QPushBotton。
属性编辑器
属性编辑器是界面设计时最常用到的编辑器,它显示某个选中的组件或窗体的各种属性及其取值,可以在属性编辑器里修改这些属性的值。
例如:在Qt的第一个程序HelloWorld的字体调节或者上图我们将PushButton按钮的名称改为关闭,均可以在属性修改器中修改值。
属性分为多个组,实际上表示了类的继承关系将,由上图将所有的属性叠加起来可以看出QLabel 的继承关系是QObject→QWidget→QFrame→QLabel。
objectName 表示组件的对象名称,界面上的每个组件都需要一个唯一的对象名称,以便被引用。
布局和对象设计工具栏
布局和界面设计工具栏上的按钮主要实现布局和界面设计。
例如:我们拖拽了两个GroupBox组合框,其中一个组合框我们拖拽进一个label组件和一个push Button组件,另一个组合框我们拖拽进一个label,通过布局和对象设计工具栏调节最外面的centralWidget设置为水平布局,此时两个组合框左右放置,在对左边的组合框设置为竖直布局,此时label组件和push button组件上下放置,右边的组合框不设置,则显示打破布局的标志。
Signals 和Slots 编辑器
当Signal被触发时,与其相关联的Slot将被自动调用,从而实现了对象之间的消息传递和响应。
通过实现一个实例来加深理解,拖拽一个Label组件和一个push Button组件,将他们按照下面表格的属性进行设置:
ObjectName | 类名称 | 属性设置 |
---|---|---|
LabDemo | QLabel | Text=”Hello, World” | Font.PointSize=20 | Font.bold=true |
btnClose | QPushButton | Text=”Close” |
编辑完属性后,再为btnClose按钮增加一个单击此按钮,关闭窗口的功能,这时便可以利用Signals 和Slots 编辑器完成这个功能。
在信号与槽编辑器的工具栏上单击“Add”按钮,在出现的条目中,发送者选择btnClose,Signal 选择clicked(),接收者选择窗体MainWindow,Slot 选择close()。这样设置表示当按钮btnClose 被单击时,就执行MainWindow的close() 函数,实现关闭窗口的功能。
上面的小实例中标签的文字内容和字体被修改了,窗口标题也显示为所设置的标题,而我们并没有编写一行程序语句,Qt 是怎么实现这些功能的呢?
可以通过阅读《Qt项目源码分析》http://t.csdn.cn/i5rBN,详细的分析了Qt 创建的GUI 应用程序中各个文件的作用,剖析了可视化设计的UI 文件是如何被转换为C++ 的类定义,并自动创建界面的。这些是使用Qt Creator 可视化设计用户界面,并使各个部分融合起来运行的基本原理。
接下来我们实现分别有Qt组件和编写Qt代码实现一个相同的案例,进行对比展示:
案例介绍
程序的主要功能是对中间一个文本框的文字字体样式和颜色进行设置。
- 单击UnderLine、Italic、Bold 3 个CheckBox 时,根据其状态,设置PlainTextEdit 里的文字的字
体样式; - Black、Red、Blue 3 个RadioButton 是互斥选择的,单击某个RadioButton 时,设置文字的颜色;
- 单击“确定”“取消”或“退出”按钮时,关闭窗口,退出程序。
Qt组件实现
创建一个Widget Application 项目text,在创建窗体时选择基类QDialog,生成的类命名为Dialog,并选择生成窗体。
-
step1: 放置组件
在窗体上放置了2 个GroupBox 组件,在groupBox1 里放置3 个CheckBox 组件,在groupBox2 里放置3 个RadioButton 组件。
拖拽进一个纯文本编辑器Plain Text Edit,再放一个Horizontal Layout 到窗体上,布局组件会以红色边框显示,同时往布局组件里拖放3 个Push Button 和2 个Horizontal Space
上图右侧Object Inspector里显示了界面上各组件之间的层次关系。
-
step2: 布局设置
通过布局和对象设计工具栏,用于调整设计器进入不同的状态,以及进行布局设计。再使用工具栏上的布局控制按钮时,只需在窗体上选中需要设计布局的组件,然后点击某个布局按钮即可。在窗体上选择组件时同时按住Ctrl 键,可以实现组件多选,选择某个容器类组件,相当于选择了其内部的所有组件。选中groupBox1,然后单击“Lay Out Horizontally”工具栏按钮,就可以对groupBox1 内的3 个CheckBox 水平布局,同样的方法也使,groupBox2 里的3 个
RadioButton 水平布局,随后还需为窗体指定一个总的布局。选中窗体(即不要选择任何组件),单击工具栏上的“Lay OutVertically”按钮,使4 个组件垂直分布。这样布局后,当窗体大小改变时,各个组件都会自动改变大小。
在Qt组件实现可视化设计布局时,要善于利用水平和垂直空格组件,善于设置组件的最大、最小宽度和高度来实现某些需要的布局效果。
-
step3: 属性设置
在界面设计时,对需要访问的组件修改其objectName,如各个按钮、需要读取输入的编辑框、需要显示结果的标签等,以便在程序里区分。对于不需要程序访问的组件则无需修改其objectName。对上图中几个主要组件的命名、属性设置见下表。
对象名 类名称 属性设置 txtEdit QPlainTextEdit Text="Hello, WorldIt is my demo. " Font.PointSize=20 chkBoxUnder QCheckBox Text=“Underline” chkBoxItalic QCheckBox Text=“Italic” chkBoxBold QCheckBox Text=“Bold” rBtnBlack QRadioButton Text=“Black” rBtnRed QRadioButton Text=“Red” rBtnBlue QRadioButton Text=“Blue” btnOK QPushButton Text=“确定” btnCancel QPushButton Text=“取消” btnClose QPushButton Text=“退出” Dialog Dialog windowTitle=“Dialog by Designer” -
step4: 字体样式设置
窗体在设计模式下,选中chkBoxUnder 组件,单击右键调出其快捷菜单。在快捷菜单中单击菜单项“Go to slot…”(中文状态为“转到槽”),选择clicked(bool),然后单击“OK”按钮。同时,在dialog.cpp 文件中自动添加了函数on_chkBoxUnder_clicked(bool) 的框架,在此函数中添加
如下的代码,实现文本框字体下划线的控制。void Dialog::on_chkBoxUnder_clicked(bool checked) { QFont font=ui->txtEdit->font(); font.setUnderline(checked); ui->txtEdit->setFont(font); }
以同样的方法为Italic 和Bold 两个CheckBox 设计槽函数,编译后运行,发现已经实现了修改字体的下划线、斜体、粗体属性的功能,说明信号与槽函数已经关联了。
-
step5: 字体颜色设置
设置字体的3 个RadioButton 是互斥性选择的,即一次只有一个RadioButton 被选中,虽然也可以采用可视化设计的方式设计其clicked() 信号的槽函数,但是这样就需要生成3 个槽函数。这里可以简化设计,即设计一个槽函数,将3 个RadioButton 的clicked() 信号关联到这一个槽函数。
为此,在Dialog类的private slots 部分增加一个槽函数定义如下:
void setTextFontColor();
将鼠标光标移动到这个函数的函数名上面,单击右键,在弹出的快捷菜单中选择“Refactor”→“在Dialog.cpp 中添加定义”,就可以在Dialog.cpp 文件中自动为函数setTextFontColor() 生成一个函数框架。在Dialog.cpp 文件中,为setTextFontColor() 编写实现代码如下:
void Dialog::setTextFontColor() { QPalette plet=ui->txtEdit->palette(); if (ui->rBtnBlue->isChecked()) plet.setColor(QPalette::Text,Qt::blue); else if (ui->rBtnRed->isChecked()) plet.setColor(QPalette::Text,Qt::red); else if (ui->rBtnBlack->isChecked()) plet.setColor(QPalette::Text,Qt::black); else plet.setColor(QPalette::Text,Qt::black); ui->txtEdit->setPalette(plet); }
由于这个槽函数是自定义的,所以不会自动与RadioButton 的clicked() 事件关联,此时编译后运行程序不会实现改变字体颜色的功能。需要在MainWindow的构造函数中(Dialog.cpp中)手工进行关联,代码如下:
Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{
ui->setupUi(this);
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
}
step7: 三个按钮的功能设计
Dialog 是从QDialog 继承而来的,QDialog 提供了accept()、reject()、close() 等槽函数来表示这三种状态,只需将按钮的clicked() 信号与相应槽函数关联即可。下面采用可视化的方式,将按钮的clicked() 信号与这些槽函数关联起来。在UI 设计器里,单击上方工具栏里的“Edit Signals/Slots”按钮,窗体进入信号与槽函数编辑状态,点击确定按钮,向下拉到空白区域,出现弹窗左侧的列表框里显示了btnOK 的信号,选择clicked(),右边的列表框里显示了Dialog 的槽函数,选择accept(),单击“OK”按钮。同样的方法可以将btnCancel 的clicked() 信号与Dialog 的reject() 槽函数关联,将btnClose的clicked() 信号与Dialog 的close() 槽函数关联。注意,操作退出时没有close() 槽函数,需要勾选下方的“显示从QWidget 继承的信号和槽”才会出现close() 函数。
设置完3 个按钮的信号与槽关联之后,在窗体下方的Signals 和Slots 编辑器里也显示了这3个关联。
此时编译运行,就会发现这个实例就设计完成了!!!
Qt代码实现
上面我们利用足迹成功实现了实例,接下来我们编写代码来完成实例
UI 的可视化设计是对用户而言的,其实底层都是C++ 的代码实现,只是Qt 巧妙地进行了处理,让用户省去了很多繁琐的界面设计工作。由于界面设计的底层其实都是由C++ 语言实现的,底层实现的功能比可视化设计更加强大和灵活。某些界面效果是可视化设计无法完成的,或者某些人习惯了用纯代码的方式来设计界面,就可以采用纯代码的方式设计界面,如Qt 自带的实例基本都是用纯代码方式实现用户界面的。所以这里再通过用纯代码方式实现上面的实例,通过实例了解用纯代码设计UI 的基本原理。与前面的可视化UI 设计相对应,且称之为代码化UI 设计。
- step1: 建立工程
首先建立一个Widget Appliation 项目samp,在创建项目向导中选择基类时,选择基类QDialog,新类的名称命名为QWDlgManual,关键是取消创建窗体,即不勾选“Generate form”(创建界面)复选框。创建后的项目文件目录树下没有.ui 文件。
-
step2: 完善 qwdlgmanual.h 中的 QWDlgManual类
-
完善头文件:因为有用到的命令按钮有checkbox、radio button、push button和纯文本编辑器Plain Text Edit,故需要导入头文件
#include <QCheckBox> #include <QRadioButton> #include <QPlainTextEdit> #include <QPushButton>
-
完善类: 因为用到了三个checkbox、三个radio button和三个push button 以及一个纯文本编辑器,故需要声明了界面上的各个组件的指针变量,这些界面组件都需要在QWDlgManual 类的构造函数里创建并在窗体上布局。定义两个函数,iniUI() 用来界面布局与初始化,并完成布局和属性设置,
iniSignalSlots() 用来完成所有的信号与槽函数的关联。QCheckBox *chkBoxUnder; QCheckBox *chkBoxItalic; QCheckBox *chkBoxBold; QRadioButton *rBtnBlack; QRadioButton *rBtnRed; QRadioButton *rBtnBlue; QPlainTextEdit *txtEdit; QPushButton *btnOK; QPushButton *btnCancel; QPushButton *btnClose; void iniUI();//界面创建与布局初始化 void iniSignalSlots();//初始化信号与槽的链接
-
完善功能:在private slots 部分声明了4 个槽函数,分别是3 个CheckBox 的响应槽函数,以及3 个颜色设置的RadioButton 的共同响应槽函数,。
private slots: void on_chkBoxUnder(bool checked); //Underline 的clicked(bool)信号的槽函数 void on_chkBoxItalic(bool checked);//Italic 的clicked(bool)信号的槽函数 void on_chkBoxBold(bool checked); //Bold 的clicked(bool)信号的槽函数 void setTextFontColor(); //设置字体颜色
-
-
step3: 完善 qwdlgmanual.cpp 中的 QWDlgManual类的各种功能
-
完善初始化函数
QWDlgManual::QWDlgManual(QWidget *parent): QDialog(parent) { iniUI(); //界面创建与布局 iniSignalSlots(); //信号与槽的关联 setWindowTitle("Form created mannually"); }
-
完善三个信号的槽函数
void QWDlgManual::on_chkBoxUnder(bool checked) { QFont font=txtEdit->font(); font.setUnderline(checked); // 设置字体下划线 txtEdit->setFont(font); } void QWDlgManual::on_chkBoxItalic(bool checked) { QFont font=txtEdit->font(); font.setItalic(checked); // 设置斜线字体 txtEdit->setFont(font); } void QWDlgManual::on_chkBoxBold(bool checked) { QFont font=txtEdit->font(); font.setBold(checked); // 设置加粗 txtEdit->setFont(font); }
-
完善字体颜色设置函数
// 三个颜色不能同时选择,利用if条件判断当谁被选中时将颜色设置过去 void QWDlgManual::setTextFontColor() { QPalette plet=txtEdit->palette(); if (rBtnBlue->isChecked()) plet.setColor(QPalette::Text,Qt::blue); else if (rBtnRed->isChecked()) plet.setColor(QPalette::Text,Qt::red); else if (rBtnBlack->isChecked()) plet.setColor(QPalette::Text,Qt::black); else plet.setColor(QPalette::Text,Qt::black); txtEdit->setPalette(plet); }
-
完善界面创建与布局函数
// 界面布局与实例化对象 void QWDlgManual::iniUI() { //创建 Underline, Italic, Bold 3 个CheckBox,并水平布局 chkBoxUnder=new QCheckBox(tr("Underline")); chkBoxItalic=new QCheckBox(tr("Italic")); chkBoxBold=new QCheckBox(tr("Bold")); QHBoxLayout *HLay1=new QHBoxLayout; HLay1->addWidget(chkBoxUnder); HLay1->addWidget(chkBoxItalic); HLay1->addWidget(chkBoxBold); //创建 Black, Red, Blue 3 个RadioButton,并水平布局 rBtnBlack=new QRadioButton(tr("Black")); rBtnBlack->setChecked(true); rBtnRed=new QRadioButton(tr("Red")); rBtnBlue=new QRadioButton(tr("Blue")); QHBoxLayout *HLay2=new QHBoxLayout; HLay2->addWidget(rBtnBlack); HLay2->addWidget(rBtnRed); HLay2->addWidget(rBtnBlue); //创建确定, 取消, 退出3 个 PushButton, 并水平布局 btnOK=new QPushButton(tr("确定")); btnCancel=new QPushButton(tr("取消")); btnClose=new QPushButton(tr("退出")); QHBoxLayout *HLay3=new QHBoxLayout; HLay3->addStretch(); HLay3->addWidget(btnOK); HLay3->addWidget(btnCancel); HLay3->addStretch(); HLay3->addWidget(btnClose); //创建文本框,并设置初始字体 txtEdit=new QPlainTextEdit; txtEdit->setPlainText("Hello world\n\nIt is my demo"); QFont font=txtEdit->font(); //获取字体 font.setPointSize(20);//修改字体大小 txtEdit->setFont(font);//设置字体 //创建垂直布局,并设置为主布局 QVBoxLayout *VLay=new QVBoxLayout; VLay->addLayout(HLay1); //添加字体类型组 VLay->addLayout(HLay2);//添加字体颜色组 VLay->addWidget(txtEdit);//添加PlainTextEdit VLay->addLayout(HLay3);//添加按键组 setLayout(VLay); //设置为窗体的主布局 }
-
完成信号和槽的关联的函数
void QWDlgManual::iniSignalSlots() { //三个颜色 QRadioButton 的clicked()信号与setTextFontColor()槽函数关联 connect(rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor())); connect(rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor())); connect(rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor())); //三个字体设置的 QCheckBox 的clicked(bool)信号与相应的槽函数关联 connect(chkBoxUnder,SIGNAL(clicked(bool)),this,SLOT(on_chkBoxUnder(bool))); connect(chkBoxItalic,SIGNAL(clicked(bool)),this,SLOT(on_chkBoxItalic(bool))); connect(chkBoxBold,SIGNAL(clicked(bool)),this,SLOT(on_chkBoxBold(bool))); //三个按钮的信号与窗体的槽函数关联 connect(btnOK,SIGNAL(clicked()),this,SLOT(accept())); connect(btnCancel,SIGNAL(clicked()),this,SLOT(reject())); connect(btnClose,SIGNAL(clicked()),this,SLOT(close())); }
最终便于运行:
-