Web上关于 QT 项目中 namesapce Ui 的理解与分析过于杂乱,在此从零开始理解一下为什么这么写。(文字描述较多,请耐心阅读。)

目录

一、项目的区别

1、Qt Empty Application

2、Qt Widgets Application

3、区别

二、为什么使用 namespace Ui ?

1、ui_yourWidget.h

2、优化

3、namespace Ui

 三、总结


一、项目的区别

我们知道,在 VS 上安装好 QT 的插件后,就能新建 QT 项目。其中有多种项目,许多教程都以  WidgetApplication 来做一个基本的演示。

namespace Ui namespace Ui 不符合编码规范_c++

 关于 namespace Ui 的故事从这里就开始了。

1、Qt Empty Application

如果我们选择了“Qt Empty Application”,那么,我们会得到一个文件都没有的空项目。

2、Qt Widgets Application

如果我们选择了“Qt Widgets Application”,那么,我们会得到包含几个初始文件的项目。

3、区别

以上两种项目最大区别就是:Empty Application 没有使用 QT designer,而 Widgets Application 需要使用 QT designer 来编辑 GUI 界面

啥意思呢?

就是如果选择 Widgets Application,就可以直接在一个窗口上进行 GUI 编辑(QT designer),而选择 Empty Application 就只能一边在脑子里 YY,一边在代码中实现一个个组件的各种参数。

二、为什么使用 namespace Ui ?

1、ui_yourWidget.h

(1)从上面两个项目的区别中我们发现,Widgets Application 既然需要在 QT designer 上进行 GUI 设计,那么我们怎么控制/操作组件呢?

于是,QT 给了一个头文件,叫做“ui_yourWidget.h”(你写的名字是啥就是啥,但是会以“ui_”开头)。但是一开始是没有这个文件的,当我们编译运行之后,才会由 QT designer 产生这个文件。

下面是工程文件一开始的样子

namespace Ui namespace Ui 不符合编码规范_namespace Ui_02

(2)“ui_yourWidget.h”里面包含了,你在 QT designer 上添加的所有组件,并且在代码层面完成了组件的各个参数设定以及布局。

下面是“ui_yourWeight.h”:

/********************************************************************************
** Form generated from reading UI file 'yourWidget.ui'
**
** Created by: Qt User Interface Compiler version 5.13.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_YOURWIDGET_H
#define UI_YOURWIDGET_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_yourWidgetClass
{
public:
    QMenuBar *menuBar;
    QToolBar *mainToolBar;
    QWidget *centralWidget;
    QStatusBar *statusBar;

    void setupUi(QMainWindow *yourWidgetClass)
    {
        if (yourWidgetClass->objectName().isEmpty())
            yourWidgetClass->setObjectName(QString::fromUtf8("yourWidgetClass"));
        yourWidgetClass->resize(600, 400);
        menuBar = new QMenuBar(yourWidgetClass);
        menuBar->setObjectName(QString::fromUtf8("menuBar"));
        yourWidgetClass->setMenuBar(menuBar);
        mainToolBar = new QToolBar(yourWidgetClass);
        mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
        yourWidgetClass->addToolBar(mainToolBar);
        centralWidget = new QWidget(yourWidgetClass);
        centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
        yourWidgetClass->setCentralWidget(centralWidget);
        statusBar = new QStatusBar(yourWidgetClass);
        statusBar->setObjectName(QString::fromUtf8("statusBar"));
        yourWidgetClass->setStatusBar(statusBar);

        retranslateUi(yourWidgetClass);

        QMetaObject::connectSlotsByName(yourWidgetClass);
    } // setupUi

    void retranslateUi(QMainWindow *yourWidgetClass)
    {
        yourWidgetClass->setWindowTitle(QCoreApplication::translate("yourWidgetClass", "yourWidget", nullptr));
    } // retranslateUi

};

namespace Ui {
    class yourWidgetClass: public Ui_yourWidgetClass {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_YOURWIDGET_H

(3)为了对用户“隐藏”具体的实现细节,让用户专注于逻辑设计,QT 设置了一个命名空间,让用户在外部类使用该类

“ui_yourWidget.h”在 namespace Ui 中声明了类 Ui::yourWidgetClass,公有继承于 Ui_yourWidgetClass(在 QT designer 上设计的 gui 的实现类)。

因此,在“yourWidget.h”(自定义类的头文件)中,只需要 include "ui_yourWidget.h",就可以使用"ui_yourWidget.h"内的类 Ui::yourWidgetClass。

然后就可以在我们的自定义类内,添加成员对象“Ui::yourWidgetClass ui”,就可以实现“通过对象 ui 控制组件”

2、优化

我们都知道,如果更改了一个头文件中的任何一点代码,都会导致所有include了这个头文件的cpp文件重新编译,如果工程较大,这将消耗许多的时间。

为了降低编译时间以及其他优化,我们采用“Pimpl”设计模式。(Pointer Implementation)

详见:

(1)简单来说就是,将成员对象定义为指针类型,将不会受到头文件修改带来的影响,减少编译时间。其主要作用是解开类的使用接口和实现的耦合

(2)前面说到的,QT 隐藏了窗口的具体实现细节,其实就是“Pimpl”的设计思想中的一部分。

因此,我们将代码做如下修改:

原来的:(第一种)

namespace Ui namespace Ui 不符合编码规范_c++_03

修改后:(第二种)

namespace Ui namespace Ui 不符合编码规范_namespace Ui_04

这样就完成了“Pimpl”。

3、namespace Ui

到目前为止,我们已经解决了在“ui_yourWidget.h”中的 namespace Ui 的问题:知道了在“ui_yourWidget.h”中使用 namespace Ui 只是为了隐藏其中的 Ui_yourWidgetClass 类,从而不让用户知道有这么一个真正的实现类。

但是还有一个问题,观察别人的代码,我们通常在“yourWidget.h”中也看到了“namespace Ui”,这是为啥呢?

很简单,单纯的是因为没有 include "ui_yourWidget.h"。

没有 include,就没有其内的 Ui 命名空间,也就用不了那个真正的实现类。

因此,在“yourWidget.h”内进行一个 namespace Ui 的声明,然后在“yourWidget.cpp”内include "ui_yourWidget.h"即可。

看起来是不是多此一举,在我未认识到其他原因之前,姑且认为是这样的。

下面给出代码:(第三种)

namespace Ui namespace Ui 不符合编码规范_namespace Ui_05

 三、总结

第二三种较第一种则多了“Pimpl”的设计思想,减少了编译时间。

前面总共三种代码写法,个人认为后两种本质上是一致的,或许第三种比较装逼吧。