赞
踩
创建Qt项目,并用Qt Designer对窗体进行可视化设计,保存之后生成对应的项目文件。本文分别分析各个文件的内容及其功能,以及它们是如何联系在一起工作,实现界面的创建与显示的。
widget.h 文件是窗体类的头文件。在创建项目时,选择窗体基类是 QWidget,在 widget.h 中定义了一个继承自 QWidget 的类 Widget。
下面是 widget.h 文件的内容:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; }; #endif // WIDGET_H
widget.h 文件有几个重要的部分。
代码中有如下的一个 namespace 声明:
namespace Ui {
class Widget;
}
这是声明了一个名称为 Ui 的命名空间(namespace),包含一个类 Widget。但是这个类 Widget 并不是本文件里定义的类 Widget,而是 ui_widget.h 文件里定义的类,用于描述界面组件的。这个声明相当于一个外部类型声明(具体要看完 ui_widget.h 文件内的解释之后才能搞明白)。
Widget 类的定义
widget.h 文件的主体部分是一个继承于 QWidget 的类 Widget 的定义,也就是本实例的窗体类。
在 Widget 类中使用了宏 Q_OBJECT,这是使用 Qt 的信号与槽(signal 和 slot)机制的类都必须加入的一个宏(信号与槽在后面详细介绍)。
在 public 部分定义了 Widget 类的构造函数和析构函数。
在 private 部分又定义了一个指针。
Ui::Widget *ui;
这个指针是用前面声明的 namespace Ui 里的 Widget 类定义的,所以指针 ui 是指向可视化设计的界面,后面会看到要访问界面上的组件,都需要通过这个指针 ui。
widget.cpp 文件是类 Widget 的实现代码,下面是 widget.cpp 文件的内容。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
注意到,在这个文件的包含文件部分自动加入了如下一行内容:
#include "ui_widget.h"
这个就是 Qt 编译生成的与 UI 文件 widget.ui 对应的类定义文件。
目前只有构造函数和析构函数。其中构造函数头部是:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
其意义是:执行父类 QWidget 的构造函数,创建一个 Ui::Widget 类的对象 ui。这个 ui 就是 Widget 的 private 部分定义的指针变量 ui。
构造函数里只有一行语句:
ui->setupUi(this)
它是执行了 Ui::Widget 类的 setupUi() 函数,这个函数实现窗口的生成与各种属性的设置、信号与槽的关联(后面会具体介绍)。
析构函数只是简单地删除用 new 创建的指针 ui。
所以,在 ui_widget.h 文件里有一个 namespace 名称为 Ui,里面有一个类 Widget 是用于描述可视化设计的窗体,且与 widget.h 里定义的类同名。在 Widget 类里访问 Ui::Widget 类的成员变量或函数需要通过 Widget 类里的 ui 指针,如同构造函数里执行 ui->setupUi( this) 函数那样。
widget.ui 是窗体界面定义文件,是一个 XML 文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用UI设计器可视化设计的界面都由 Qt 自动解析,并以 XML 文件的形式保存下来。在设计界面时,只需在 UI 设计器里进行可视化设计即可,而不用管 widget.ui 文件是怎么生成的。
下面是 widget.ui 文件的内容:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Widget</class> <widget class="QWidget" name="Widget"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>336</width> <height>216</height> </rect> </property> <property name="windowTitle"> <string>My First Demo</string> </property> <widget class="QLabel" name="Lablabel"> <property name="geometry"> <rect> <x>100</x> <y>70</y> <width>141</width> <height>61</height> </rect> </property> <property name="font"> <font> <pointsize>12</pointsize> <weight>75</weight> <bold>true</bold> </font> </property> <property name="text"> <string>Hello,World</string> </property> </widget> <widget class="QPushButton" name="btnClose"> <property name="geometry"> <rect> <x>210</x> <y>150</y> <width>75</width> <height>23</height> </rect> </property> <property name="text"> <string>Close</string> </property> </widget> </widget> <layoutdefault spacing="6" margin="11"/> <resources/> <connections> <connection> <sender>btnClose</sender> <signal>clicked()</signal> <receiver>Widget</receiver> <slot>close()</slot> <hints> <hint type="sourcelabel"> <x>247</x> <y>161</y> </hint> <hint type="destinationlabel"> <x>167</x> <y>107</y> </hint> </hints> </connection> </connections> </ui>
ui_widget.h 是在对 widget.ui 文件编译后生成的一个文件,ui_widget.h 会出现在编译后的目录下,或与 widget.ui 同目录(与项目的 shadow build 编译设置有关)。
文件 ui_widget.h 并不会出现在 Qt Creator 的项目文件目录树里,当然,可以手工将 ui_widget.h 添加到项目中。方法是在项目文件目录树上,右击项目名称节点,在调出的快捷菜单中选择“Add Existing Files…”,找到并添加 ui_widget.h 文件即可。
注意,ui_widget.h 是对 widget.ui 文件编译后自动生成的,widget.ui 又是通过 UI 设计器可视化设计生成的。所以,对 ui_widget.h 手工进行修改没有什么意义,所有涉及界面的修改都应该直接在UI 设计器里进行。所以,ui_widget.h 也没有必要添加到项目里。
下面是 ui_widget.h 文件的内容:
/******************************************************************************** ** Form generated from reading UI file 'widget.ui' ** ** Created by: Qt User Interface Compiler version 5.9.1 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ #ifndef UI_WIDGET_H #define UI_WIDGET_H #include <QtCore/QVariant> #include <QtWidgets/QAction> #include <QtWidgets/QApplication> #include <QtWidgets/QButtonGroup> #include <QtWidgets/QHeaderView> #include <QtWidgets/QLabel> #include <QtWidgets/QPushButton> #include <QtWidgets/QWidget> QT_BEGIN_NAMESPACE class Ui_Widget { public: QLabel *label; QPushButton *btnClose; void setupUi(QWidget *Widget) { if (Widget->objectName().isEmpty()) Widget->setObjectName(QStringLiteral("Widget")); Widget->resize(336, 216); label = new QLabel(Widget); label->setObjectName(QStringLiteral("label")); label->setGeometry(QRect(100, 70, 141, 61)); QFont font; font.setPointSize(12); font.setBold(true); font.setWeight(75); label->setFont(font); btnClose = new QPushButton(Widget); btnClose->setObjectName(QStringLiteral("btnClose")); btnClose->setGeometry(QRect(210, 150, 75, 23)); retranslateUi(Widget); QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close())); QMetaObject::connectSlotsByName(Widget); } // setupUi void retranslateUi(QWidget *Widget) { Widget->setWindowTitle(QApplication::translate("Widget", "My First Demo", Q_NULLPTR)); label->setText(QApplication::translate("Widget", "Hello\357\274\214World", Q_NULLPTR)); btnClose->setText(QApplication::translate("Widget", "Close", Q_NULLPTR)); } // retranslateUi }; namespace Ui { class Widget: public Ui_Widget {}; } // namespace Ui QT_END_NAMESPACE #endif // UI_WIDGET_H
查看 ui_widget.h 文件的内容,发现它主要做了以下的一些工作:
定义了一个类 Ui_Widget,用于封装可视化设计的界面。
自动生成了界面各个组件的类成员变量定义。在 public 部分为界面上每个组件定义了一个指针变量,变量的名称就是设置的 objectName。比如,在窗体上放置了一个 QLabel 和一个 QPushButton 并命名后,自动生成的定义是:
QLabel *LabDemo;
QPushButton *btnClose;
定义了 setupUi() 函数,这个函数用于创建各个界面组件,并设置其位置、大小、文字内容、字体等属性,设置信号与槽的关联。setupUi() 函数体的第一部分是根据可视化设计的界面内容,用 C++ 代码创建界面上各组件,并设置其属性。
接下来,setupUi() 调用了函数 retranslateUi(Widget),用来设置界面各组件的文字内容属性,如标签的文字、按键的文字、窗体的标题等。将界面上的文字设置的内容独立出来作为一个函数 retranslateUi(),在设计多语言界面时会用到这个函数。
setupUi() 函数的第三部分是设置信号与槽的关联,本文件中有以下两行:
QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
QMetaObject::connectSlotsByName(Widget);
第1 行是调用 connect() 函数,将在 UI 设计器里设置的信号与槽的关联转换为语句。这里是将 btnClose 按键的 clicked() 信号与窗体 Widget 的 close() 槽函数关联起来,就是在图 4 中设置的信号与槽的关联的程序语句实现。这样,当单击 btnClose 按钮时,就会执行 Widget 的 close() 槽函数,而 close() 槽函数的功能是关闭窗口。
第 2 行是设置槽函数的关联方式,用于将 UI 设计器自动生成的组件信号的槽函数与组件信号相关联。
所以,在Widget 的构造函数里调用 ui->setupUI(this),就实现了窗体上组件的创建、属性设置、信号与槽的关联。
定义 namespace Ui,并定义一个从Ui_Widget 继承的类Widget。
namespace Ui {
class Widget: public Ui_Widget {};
}
提示:ui_widget.h 文件里实现界面功能的类是 Ui_Widget。再定义一个类 Widget 从 Ui_Widget 继承而来,并定义在 namespace Ui 里,这样 Ui:: Widget 与 widget.h 里的类 Widget 同名,但是用 namespace 区分开来。所以,界面的 Ui:: Widget 类与文件 widget.h 里定义的 Widget 类实际上是两个类,但是 Qt 的处理让用户感觉不到 Ui:: Widget 类的存在,只需要知道在 Widget 类里用 ui 指针可以访问可视化设计的界面组件就可以了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。