[QT | C++] 关于 namespace Ui 的理解

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 的故事从这里就开始了。

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 产生这个文件。

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

(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)

详见:https://blog.csdn.net/lihao21/article/details/47610309

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

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

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

原来的:(第一种)

修改后:(第二种)

这样就完成了“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"即可。

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

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

 三、总结

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

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

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值