空项目自带的文件
- 为了更深入地认识,这里不使用默认的空窗口,而是自己写一个窗口
添加一个窗口
- 添加窗口后将生成一个
Widget.ui
文件,双击就会打开Designer界面,可在界面中拖动控件编辑程序。这里使用Designer添加一个按钮
添加一个按钮
- 编译
Widget.ui
文件,生成ui_Widget.h
文件,将其导入到项目中
/********************************************************************************
** Form generated from reading UI file 'Widget.ui'
**
** Created by: Qt User Interface Compiler version 5.10.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/QPushButton>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Form
{
public:
QPushButton *pushButton;
void setupUi(QWidget *Form)
{
if (Form->objectName().isEmpty())
Form->setObjectName(QStringLiteral("Form"));
Form->resize(400, 300);
pushButton = new QPushButton(Form);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(100, 80, 75, 23));
retranslateUi(Form);
QMetaObject::connectSlotsByName(Form);
} // setupUi
void retranslateUi(QWidget *Form)
{
Form->setWindowTitle(QApplication::translate("Form", "Form", nullptr));
pushButton->setText(QApplication::translate("Form", "PushButton", nullptr));
} // retranslateUi
};
namespace Ui {
class Form: public Ui_Form {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_WIDGET_H
- 可以发现在Designer界面添加的按钮,实际上会在
setupUi
函数中生成对应的代码,所以setupUi
可以简单理解为构造函数,它的作用就是把Designer界面内容显示出来。如果把按钮从Designer中删掉,重新编译后,ui_Widget.h
内容如下(QPushButton相关代码被删除)
/********************************************************************************
** Form generated from reading UI file 'Widget.ui'
**
** Created by: Qt User Interface Compiler version 5.10.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/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Form
{
public:
void setupUi(QWidget *Form)
{
if (Form->objectName().isEmpty())
Form->setObjectName(QStringLiteral("Form"));
Form->resize(400, 300);
retranslateUi(Form);
QMetaObject::connectSlotsByName(Form);
} // setupUi
void retranslateUi(QWidget *Form)
{
Form->setWindowTitle(QApplication::translate("Form", "Form", nullptr));
} // retranslateUi
};
namespace Ui {
class Form: public Ui_Form {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_WIDGET_H
- 这里还需要解释的是
namespace Ui
,其中的class Form
其实就是一个继承了Ui_Form
的空类。之后将在Widget.h
中声明一个指向Ui::Form
的指针,用于操控界面。虽然Form
是空类,但它继承了Ui_Form
,因此Ui_Form
中的所有非私有的内容都能用
- 随后添加一个头文件
Widget.h
和源文件Widget.cpp
(也可以取其他文件名)
添加头文件和源文件之后的项目结构
-
Widget.h
内容如下,先做一个namespace的前置声明,private作用域中添加了一个指向Ui::Form
类型的指针ui
,可以将其理解为指向界面的指针。在源文件中用它可以直接访问界面中的控件,如访问之前添加过的按钮,只需要ui->pushButton
。这样做的好处就是不需要包含ui_Widget.h
,降低了耦合性(每次Designer界面改变都会重新编译ui_Widget.h
),这种分离接口和实现的手法类似于PImpl
#ifndef WIDGET_H
#define WIDGET_H
#include <QMainWindow> // 窗口派生自QMainWindow
namespace Ui { // 前置声明命名空间
class Form;
}
class widget : public QMainWindow // 继承
{
Q_OBJECT // 必须添加的宏
public:
explicit widget(QWidget *parent = 0); // 必须指定显式构造
~widget();
private:
Ui::Form *ui; // 指向Designer界面的指针
};
#endif // WIDGET_H
#define Q_OBJECT \
public: \
Q_OBJECT_CHECK \
QT_WARNING_PUSH \
Q_OBJECT_NO_OVERRIDE_WARNING \
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
QT_TR_FUNCTIONS \
private: \
Q_OBJECT_NO_ATTRIBUTES_WARNING \
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
QT_WARNING_POP \
struct QPrivateSignal {}; \
QT_ANNOTATE_CLASS(qt_qobject, "")
- QObject类是Qt所有类的基类,只要是QObject的子类就要在第一行代码写上
Q_OBJECT
,它提供信号槽机制、国际化机制以及 Qt 提供的不基于 C++ RTTI 的反射能力,但即使不使用这些操作最好也添加Q_OBJECT
以防出错。这个宏由moc(可以将其理解为一种预处理器) 做特殊处理,moc会处理标记了Q_OBJECT
的头文件(不处理cpp文件),生成moc_
前缀的文件
-
Widget.cpp
内容如下,这里调用setupUi
相当于ui_Widget.h
中的构造函数,用于显示Widget.ui
界面的内容
#include "Widget.h"
#include "ui_Widget.h"
widget::widget(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Form)
{
ui->setupUi(this);
}
widget::~widget()
{
delete ui;
}
- 利用
ui
指针也可以访问控件来修改内容,比如在Designer界面中的按钮控件pushButton
文本默认是PushButton
,在Widget.cpp
中使用ui->pushButton->setText
即可修改按钮文本,类似也可以自己添加其他控件
#include "Widget.h"
#include "ui_Widget.h"
widget::widget(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Form)
{
ui->setupUi(this);
ui->pushButton->setText("new");
}
widget::~widget()
{
delete ui;
}
- 也可以不通过
ui
指针,也就是不利用Desiner界面,直接用代码生成,比如直接在Widget.cpp
的构造函数中添加控件
widget::widget(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Form)
{
ui->setupUi(this);
QVBoxLayout* layout = new QVBoxLayout(this);
QPushButton* btn = new QPushButton(this);
btn->setText("test");
layout->addWidget(btn);
QWidget *centralWidget = new QWidget();
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
}
- 随后在
main.cpp
中包含Widget.h
头文件,直接声明一个对象再调用show()
就显示了我们自己写的窗口
#include "QtGuiApplication1.h"
#include "Widget.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QtGuiApplication1 w;
widget w;
w.show();
return a.exec();
}
网友评论