美文网首页
Qt程序的基本结构

Qt程序的基本结构

作者: downdemo | 来源:发表于2018-09-14 16:37 被阅读303次
    • 以VS的空项目为例,新建一个Qt界面程序
    空项目自带的文件
    • 为了更深入地认识,这里不使用默认的空窗口,而是自己写一个窗口
    添加一个窗口
    • 添加窗口后将生成一个Widget.ui文件,双击就会打开Designer界面,可在界面中拖动控件编辑程序。这里使用Designer添加一个按钮
    添加一个按钮
    • 编译Widget.ui文件,生成ui_Widget.h文件,将其导入到项目中
    • 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
    
    • 这里要解释的是Q_OBJECT,它的本质是一个宏
    #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();
    }
    

    相关文章

      网友评论

          本文标题:Qt程序的基本结构

          本文链接:https://www.haomeiwen.com/subject/bzwogftx.html