此帖刚开始是从别的地方转载过来的,考完也是云里雾里,觉得有些地方还是不甚明白,刚昨晚一些深刻的研究,也算是对自己长时间的疑惑有个交代了,下面的东西是我另加的,希望能解答和我有相同疑惑的人的问题,如有还有哪里不明白,欢迎大家和我讨论,别向我扔臭鸡蛋哈~~
用最新的QtCreator选择GUI的应用会产生含有如下文件的工程
下面就简单分析下各部分的功能。
下面是mainwindow.h中的内容
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QtGui/QMainWindow> namespace Ui { class MainWindow; } /* 大家注意这里 这里只是一个声明,此文件中并没有#include “ui_mainwindow.h” 但是在类定义中出现了Ui::MainWindow的引用,所以此处必须提前声明。此处令人比较迷惑,后面我会给大家介绍一种新方法,可以完全避免这种迷惑人的代码写法~~~ */ class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
声明namespace Ui是因为要调用Ui中的MainWindow,此MainWindow非彼MainWindow,后面涉及的*ui指针会调用它!
关于Q_OBJECT就不说了,Qt中与signal和slot相关的类都要这么声明下。
仔细看出了构造,析构就没啥了,只有那么个*ui!不过现在如果运行下,也只会生成个窗体而已。
下面来看构造函数和析构函数,其实也就是mainwindow.c
#include "mainwindow.h" #include "ui_mainwindow.h" //这里才包含了文件“ui_mainwindow.h”。我们知道 #include这条预编译命令实际上就是把所需要包含进来的文件内容简单的粘贴过来而//已~~ 但是此处将两个h文件中的内容复制粘贴过来之后我们会发现 Ui 这个命名空间被定义了两次。 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } 一次是在mainwindow.h中 namespace Ui { class MainWindow; } 另外一次是在ui_mainwindow.h中 namespace Ui { class MainWindow: public Ui_MainWindow {}; } // namespace Ui 也就是说,Qt在同一个文件内对同一个命名空间进行两次定义,目前我在网上还没查到在一个文件中对同一个命名空间进行两次定义时,C++编译系统到底会做什么的有关详细解释, 不过在此并没有产生编译错误。 在此我补充一些对命名空间的知识。 命名空间可以包含的内容有 ·变量(可以带有初始化); ·常量; ·数(可以是定义或声明); ·结构体; ·类; ·模板; ·命名空间(在一个命名空间中又定义一个命名空间,即嵌套的命名空间)。 在一个命名空间中,你声明一个int a 那么a就是实实在在会存在的,他不只是一个声明。我们来做这样一个实验 //main.cpp namespace test1{ int a; } namespace test1{ int a; } 在同一个文件中两次定义test1 这个命名空间,编译会报错。很明显 我们对a进行了两次定义。 这时大家肯定会有疑问 ,在qt 那个文件中不是一个命名空间 被定义了两次么,可是并没有报错啊答案是:因为第一个命名空间只是声明,而另外一个命名空间用来定义类! 两个命名空间看似一样,但作用不一样。 我们再做一个实验 //main.cpp namespace test1{ class test{ int a; }; } namespace test1{ class test{ int a; }; } 这次还会报错 ,因为对test进行了两次定义!!! 但是我们这样 //main.cpp namespace test1{ class test; //注意此处只是一个声明! } namespace test1{ class test{ int a; }; } 编译通过!!! 这就是qt中那个文件两次对同一个命名空间定义的道理! 我们甚至可以在一个文件里这样干: //main.cpp namespace test1{ class test; } namespace test1{ class test; } namespace test1{ class test; } namespace test1{ class test; } namespace test1{ class test{ int a; };}//只有此处是定义 其他地方都是声明!!! namespace test1{ class test; } namespace test1{ class test; } namespace test1{ class test; } 编译依然通过~~~ 顺便提一下,在同一个文件中一个类或者一个变量或者一个函数 只能被定义一次,但是可以被无限次声明~~~ 由于本人水平就是这样,qt这样做我没发现什么好处。但是这里我提供 给大家另外一种方法,可以完全绕过这种命名空间的方式: 对其他文件不要更改, 原本qt是在mainwindow.cpp中包含了这个文件,在mainwindow.h中只做了声明, 在mainwindow.h 中 包含进来ui_mainwindow.h,将Ui的这个命名空间的声明直接删除即可~~
构造时在堆上new了个Ui域中的MainWindow,并调用setupUi,析构仅仅是将其delete了,还是很简单!
正如前面所述Qt很好的把ui分离了出去,前面图中的那个.ui文件就是让QtDesigner使的布局用文件!
现在运行下,会生成ui_mainwindow.h,这个里面会涉及到真正布局用的函数,也就是那个Ui域中的MainWindow.下面具体看一下,
#ifndef UI_MAINWINDOW_H #define UI_MAINWINDOW_H #include <QtCore/QVariant> #include <QtGui/QAction> #include <QtGui/QApplication> #include <QtGui/QButtonGroup> #include <QtGui/QHeaderView> #include <QtGui/QMainWindow> #include <QtGui/QMenuBar> #include <QtGui/QStatusBar> #include <QtGui/QToolBar> #include <QtGui/QWidget> QT_BEGIN_NAMESPACE class Ui_MainWindow { public: QMenuBar *menuBar; QToolBar *mainToolBar; QWidget *centralWidget; QStatusBar *statusBar; void setupUi(QMainWindow *MainWindow) { if (MainWindow->objectName().isEmpty()) MainWindow->setObjectName(QString::fromUtf8("MainWindow")); MainWindow->resize(600, 400); menuBar = new QMenuBar(MainWindow); menuBar->setObjectName(QString::fromUtf8("menuBar")); MainWindow->setMenuBar(menuBar); mainToolBar = new QToolBar(MainWindow); mainToolBar->setObjectName(QString::fromUtf8("mainToolBar")); MainWindow->addToolBar(mainToolBar); centralWidget = new QWidget(MainWindow); centralWidget->setObjectName(QString::fromUtf8("centralWidget")); MainWindow->setCentralWidget(centralWidget); statusBar = new QStatusBar(MainWindow); statusBar->setObjectName(QString::fromUtf8("statusBar")); MainWindow->setStatusBar(statusBar); retranslateUi(MainWindow); QMetaObject::connectSlotsByName(MainWindow); } // setupUi void retranslateUi(QMainWindow *MainWindow) { MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8)); Q_UNUSED(MainWindow); } // retranslateUi }; namespace Ui { class MainWindow: public Ui_MainWindow {}; } // namespace Ui QT_END_NAMESPACE #endif // UI_MAINWINDOW_H
吼吼,一下子多了不少,但其实还是很容易的。Ui_MainWindow声明了几个构件,具体我就不说了,因为也没啥可说的,它实现了setupUi函式,也就是前面那个MainWindow中调用的setupUi。
但是要说明的是QMetaObject::connectSlotsByName函式会自动连接相应名称的信号与槽,但要注意它连接的是传入的MainWindow及其子构件【不是子类】,注意前边ui->setupUi(this)中传入的this,也就是非ui域中的MainWindow,所以如果要声明signal和slot时还是要在非ui域的MainWindow中来声明,然后通过ui->xxx的形式来与GUI产生交互!如果我们在QtDesiner中拖放一个按钮然后点击go to slot就很容易印证这一点。
retranslateUi则会为ui中的构件命名,具体也不在此多说。