文章

QtUI构建流程

Qt UI 构建流程包括使用 Qt Designer 创建 .ui 文件,或用 C++ 手动创建控件和布局,并通过信号槽实现交互逻辑。

QtUI构建流程

Qt UI构建流程

Qt 的 UI 构建流程可以分为两种方式:

  • 使用 Qt Designer(.ui 文件)+ 自动生成代码

  • 使用 C++ 代码手动构建 UI(纯代码方式)

使用 Qt Designer 构建 UI(推荐方式)

Qt Designer 是什么?能做什么?

Qt Designer 是 Qt 提供的图形界面编辑器,支持通过拖拽方式设计 .ui 文件(XML 形式),再由 Qt 工具自动转换为 C++ 代码使用。

可以拖控件、布局、设定 objectName、信号槽等,而不用手动写 C++ 来 new 控件和布局。

全流程图:从 UI 设计到程序运行

1
2
3
4
5
6
7
8
9
10
11
12
13
            Qt Designer
                
           保存 .ui 文件 (XML)
                
           uicUI Compiler
                
        生成 ui_xxx.h 头文件C++
                
       MainWindow  include 并调用
                
     ui->setupUi(this) 创建并配置控件
                
           程序运行可视化 UI

项目结构与源代码

项目结构
1
2
3
4
5
6
MyProject/
├── main.cpp
├── mainwindow.h
├── mainwindow.cpp
├── mainwindow.ui        <-- Qt Designer 创建的 XML 文件
└── ui_mainwindow.h      <-- uic 自动生成
.ui 文件示例(XML 结构)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="windowTitle"><string>示例窗口</string></property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QLineEdit" name="lineEdit"/>
    </item>
    <item>
     <widget class="QPushButton" name="pushButton">
      <property name="text"><string>点击提交</string></property>
     </widget>
    </item>
    <item>
     <widget class="QLabel" name="label">
      <property name="text"><string>等待输入...</string></property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
</ui>

通过 Designer 拖拽生成了 3 个控件,并设置好名称。

mainwindow.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void handleInput();

private:
    Ui::MainWindow *ui;  // 指向 UI 控件集合
};
#endif // MAINWINDOW_H
mainwindow.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "mainwindow.h"
#include "ui_mainwindow.h"  // 包含自动生成的 UI 定义

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {

    ui->setupUi(this);  // 核心函数,初始化 UI

    connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::handleInput);
}

void MainWindow::handleInput() {
    QString text = ui->lineEdit->text();
    ui->label->setText("你输入了: " + text);
}

MainWindow::~MainWindow() {
    delete ui;
}

setupUi(this) 做了什么?

调用 setupUi(this) 会执行这些事情:

  1. 实例化控件new QLineEdit, new QPushButton, new QLabel
  2. 设置控件名称、属性(text、font、alignment 等)
  3. 配置布局(QVBoxLayout 并添加控件)
  4. 将控件添加到主窗口中心部件中
  5. 将控件地址绑定到 ui->控件名 指针

例如:

1
2
lineEdit = new QLineEdit(centralwidget);
label = new QLabel("等待输入...", centralwidget);

ui_mainwindow.h 是怎么生成的?

这是 Qt 提供的 uic 工具的职责,编译阶段自动把 XML 翻译为 C++ 类

生成内容类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace Ui {
class MainWindow;
}

class Ui_MainWindow {
public:
    QWidget *centralwidget;
    QLineEdit *lineEdit;
    QPushButton *pushButton;
    QLabel *label;
    QVBoxLayout *verticalLayout;

    void setupUi(QMainWindow *MainWindow) {
        centralwidget = new QWidget(MainWindow);
        lineEdit = new QLineEdit(centralwidget);
        pushButton = new QPushButton("点击提交", centralwidget);
        label = new QLabel("等待输入...", centralwidget);

        verticalLayout = new QVBoxLayout(centralwidget);
        verticalLayout->addWidget(lineEdit);
        verticalLayout->addWidget(pushButton);
        verticalLayout->addWidget(label);

        MainWindow->setCentralWidget(centralwidget);
    }
};

生成类 Ui_MainWindow 中的成员变量会在 MainWindow 类中通过 ui->成员名 访问。

信号与槽绑定机制

1
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::handleInput);
  • 信号(Signal):如 QPushButton::clicked
  • 槽(Slot):自定义的成员函数 handleInput()

Qt 会通过元对象系统(Meta-Object Compiler, MOC)建立运行时的连接表,实现回调。

使用 Qt Designer 的优势与适用场景

优点:

  • 快速原型设计
  • 所见即所得
  • 易于协作(UI / 逻辑分离)
  • 可视化布局调整、属性编辑

注意:

  • 所有控件必须设置 objectName 才能被 uic 正确绑定
  • 逻辑层不要在 .ui 文件中写,保持解耦
  • 修改 .ui 文件后应重新编译

小结

阶段工具/操作作用
设计Qt Designer设计 .ui(XML)
编译uic生成 ui_xxx.h
使用setupUi()实例化 UI
连接connect()绑定事件响应
运行exec()启动主循环

使用 C++ 代码手动构建 UI(纯代码方式)

在 Qt 中除了使用 Qt Designer(.ui 文件)设计 UI 外,也可以完全使用 C++ 代码手动构建 UI。这种方式灵活、无依赖 .ui 文件,适合动态控件布局、跨平台项目、嵌入式开发等场景。

核心思路

手动构建 UI 的步骤:

  1. 创建窗口类并继承 QWidgetQMainWindow
  2. 使用构造函数中手动实例化控件;
  3. 使用布局类(如 QVBoxLayout, QHBoxLayout 等)组合控件;
  4. 使用 setLayout()setCentralWidget() 设置布局;
  5. 通过信号槽连接交互逻辑。

示例:构建一个简单的登录窗口

效果展示
  • 标签:用户名、密码
  • 输入框:QLineEdit
  • 登录按钮
  • 使用垂直布局组合
完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// main.cpp
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>

class LoginWidget : public QWidget {
    Q_OBJECT

public:
    LoginWidget(QWidget* parent = nullptr) : QWidget(parent) {
        // 创建控件
        QLabel* userLabel = new QLabel("用户名:");
        QLabel* passLabel = new QLabel("密码:");

        usernameEdit = new QLineEdit;
        passwordEdit = new QLineEdit;
        passwordEdit->setEchoMode(QLineEdit::Password);

        QPushButton* loginButton = new QPushButton("登录");

        // 布局
        QVBoxLayout* mainLayout = new QVBoxLayout;

        QHBoxLayout* userLayout = new QHBoxLayout;
        userLayout->addWidget(userLabel);
        userLayout->addWidget(usernameEdit);

        QHBoxLayout* passLayout = new QHBoxLayout;
        passLayout->addWidget(passLabel);
        passLayout->addWidget(passwordEdit);

        mainLayout->addLayout(userLayout);
        mainLayout->addLayout(passLayout);
        mainLayout->addWidget(loginButton);

        setLayout(mainLayout);
        setWindowTitle("登录窗口");
        resize(300, 150);

        // 信号槽
        connect(loginButton, &QPushButton::clicked, this, &LoginWidget::handleLogin);
    }

private slots:
    void handleLogin() {
        QString username = usernameEdit->text();
        QString password = passwordEdit->text();
        if (username == "admin" && password == "123456") {
            QMessageBox::information(this, "登录成功", "欢迎," + username);
        } else {
            QMessageBox::warning(this, "登录失败", "用户名或密码错误");
        }
    }

private:
    QLineEdit* usernameEdit;
    QLineEdit* passwordEdit;
};

// 启动入口
int main(int argc, char* argv[]) {
    QApplication app(argc, argv);
    LoginWidget login;
    login.show();
    return app.exec();
}

// 类定义写在 .cpp 文件中,且用到 Q_OBJECT 宏,则需要手动 #include "xxx.moc"
#include "main.moc"

知识点解析

控件创建

控件用 new 创建,传入 this 或默认父指针。

1
QPushButton* btn = new QPushButton("点击");
布局管理

Qt 提供 QHBoxLayout, QVBoxLayout, QGridLayout, QFormLayout 等。

1
2
3
4
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(widget1);
layout->addWidget(widget2);
setLayout(layout); // QWidget专用

QMainWindow 要用:

1
setCentralWidget(widget);
信号槽连接
1
connect(button, &QPushButton::clicked, this, &Class::slotFunc);

何时用纯代码构建 UI?

场景是否推荐纯代码
UI 简单或动态生成✅ 推荐
嵌入式、无资源系统✅ 推荐
跨平台 CMake 项目✅ 推荐
需要与设计分离❌ 建议用 Qt Designer
需要美术设计师参与❌ 建议用 .ui 文件

项目结构建议

1
2
3
4
project/
├── main.cpp
├── login_widget.h
└── login_widget.cpp

将 UI 构建代码放在 login_widget.* 文件中,逻辑更清晰。

扩展建议

  • 配合样式表(setStyleSheet)自定义控件样式;
  • 支持国际化(tr());
  • 将控件封装为复用组件类。

对比

维度Qt Designer + .ui 文件纯 C++ 手动构建 UI
UI 构建方式图形界面拖拽控件,生成 .ui 文件,自动转为 C++ 类完全通过 C++ 代码手动创建控件和布局
代码位置UI 逻辑和展示分离,布局在 .ui 文件中UI 和逻辑耦合,所有内容都在 C++ 中
初学者友好性✅ 友好,图形化操作直观❌ 需要理解控件、布局的构造顺序和层次关系
修改 UI 的便捷性✅ 非常便捷,拖拽即可❌ 不方便,需逐行修改代码
可读性✅ 更清晰,结构分明❌ UI 和逻辑混在一起
灵活性❌ 差,运行时不能动态生成复杂控件树✅ 高,可根据运行时逻辑动态构建复杂界面
生成方式uic 工具自动将 .ui 文件转为头文件(ui_xxx.h不依赖生成工具,自己写全部代码
部署复杂度需打包 .ui 文件或依赖 uic 生成的代码无依赖,易于部署
定制控件集成稍复杂,需要注册自定义控件到 Qt Designer简单,自定义类直接 new 即可
适合场景设计主窗口、对话框、静态表单类 UI动态表格、复杂图形、嵌入式设备
信号槽连接可在 Designer 设置或手动写代码必须写代码手动连接
国际化支持(tr()✅ 自动支持✅ 手动写 tr()
推荐搭配.ui 文件 + QMainWindowQDialog继承自 QWidget 或其他组件类
本文由作者按照 CC BY 4.0 进行授权