Qt实战:从零构建美化登录界面

前言

很多新手学习 Qt 习惯直接复制一长串完整代码,运行成功却看不懂每一行作用。 本文换一种学习方式:迭代式开发

  1. 版本 1:最简程序,先把窗口跑起来,弄懂 Qt 程序生命周期。
  2. 版本迭代:逐个增加交互、封装类、搭建界面、优化排版、美化样式。
  3. 每一次迭代都会引出新知识点,同时对比旧方案的缺陷,理解为什么需要新方案。

一、前置基础认知

1. Qt Creator 初次启动弹窗处理

首次打开软件会弹出两个提示框:

  1. Crash Reporting(崩溃报告) :收集软件崩溃日志,直接点击 Do Not Show Again(不再显示)。
  2. Take a UI Tour?(界面导览) :软件操作引导,新手可选择跳过,点击 Do Not Show Again

2. Qt 核心应用类区分

适用场景 核心限制
QCoreApplication 控制台后台程序 不能使用任何 GUI 窗口、按钮控件
QApplication 图形界面 GUI 程序 支持窗口、控件、鼠标键盘交互,本文使用

3. qmake 工程构建流程

我们编写.pro工程文件 → 通过qmake工具自动生成Makefile → make 工具编译生成可执行程序。

日常开发不需要手动修改 Makefile,交由工具自动生成。

复制代码
//基础.pro模板
QT += core gui widgets
TARGET = QtLoginDemo
TEMPLATE = app
SOURCES += main.cpp

二、从空白窗口到精致交互

版本1:最小可用 Qt GUI 程序

目标:写出最简代码,弹出窗口,弄懂 Qt 程序运行基础框架。

cpp 复制代码
#include <QPushButton>
#include <QApplication>

int main(int argc, char *argv[])
{
    // 1. 创建唯一GUI应用实例
    QApplication a(argc, argv);
    // 2. 创建按钮控件,控件独立创建时可以直接作为顶层窗口
    QPushButton btn("测试窗口");
    // 3. 设置窗口基础属性
    btn.setWindowTitle("第一个Qt程序");
    btn.setFixedSize(400, 300);
    // 4. 显示窗口
    btn.show();
    // 5. 启动事件循环,监听界面操作
    return a.exec();
}

核心知识点

  1. QApplication a(argc, argv):一个 GUI 程序有且只能有一个实例。
  2. show():控件创建后默认隐藏,必须调用才能渲染显示。
  3. a.exec():开启事件循环。程序运行到此不会立刻退出,持续监听鼠标、窗口操作;

✅ 实验验证:删除show()看不到窗口;删除a.exec()窗口一闪而过。

运行效果:一个带文字按钮的独立窗口。

版本2:新增交互,信号槽与消息对话框

需求升级:点击按钮,弹出确认框,选择确认后关闭窗口。 新增知识点:信号与槽、connect 连接、Lambda 表达式、QMessageBox 弹窗

cpp 复制代码
#include <QPushButton>
#include <QApplication>
#include <QObject>
#include <QMessageBox>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton btn("点我退出");
    btn.setWindowTitle("第一个Qt程序");
    btn.setFixedSize(400, 300);
    // 信号槽绑定:发送者 -> 信号 -> 执行逻辑
    QObject::connect(&btn, &QPushButton::clicked, [&]{
        // 问答弹窗
        auto ret = QMessageBox::question(nullptr, "确认操作", "是否真的退出程序?");
        if(ret == QMessageBox::Yes)
        {
            btn.close();
        }
    });

    btn.show();
    return a.exec();
}

知识点梳理

  1. 信号:&QPushButton::clicked,按钮被点击时自动发出的事件。
  2. QObject::connect(发送者, 信号, 处理函数),搭建事件桥梁。
  3. [&] Lambda 引用捕获:可以直接访问外部局部变量 btn。
  4. QMessageBox::question() 弹出确认对话框,通过返回值判断用户操作。

运行测试:点击按钮弹出弹窗,选择【是】关闭窗口,选择【否】窗口保持打开。

版本3:代码封装,自定义窗口类

当前代码存在问题

所有界面代码全部写在 main.cpp 中,界面复杂时代码臃肿、难以维护。 解决方案:封装自定义窗口类 LoginWidget

新建 loginwidget.h

cpp 复制代码
#ifndef LOGINWIDGET_H
#define LOGINWIDGET_H

#include <QWidget>

class LoginWidget : public QWidget
{
    Q_OBJECT // 重要宏:启用元对象系统,支持信号槽
public:
    explicit LoginWidget(QWidget *parent = nullptr);
};

#endif // LOGINWIDGET_H

新建 loginwidget.cpp

cpp 复制代码
#include "loginwidget.h"

LoginWidget::LoginWidget(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("登录窗口");
    setFixedSize(400, 320);
}

改造 main.cpp,main 只负责启动程序

cpp 复制代码
#include <QApplication>
#include "loginwidget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    LoginWidget w;
    w.show();
    return a.exec();
}

核心知识点

  1. Q_OBJECT:只要类需要使用信号槽,必须添加。
  2. QWidget *parent:父对象参数,Qt 对象树机制,自动管理内存。
  3. 职责分离:main 负责程序启动,所有界面搭建逻辑放在自定义窗口构造函数。

运行效果:空白登录窗口,为后续搭建表单控件做准备。

版本4:搭建登录控件 + 绝对定位布局

需求:在窗口上放置标签、输入框、登录按钮,实现登录页面雏形。 新增知识点:基础控件、setGeometry() 绝对定位

cpp 复制代码
#include "loginwidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>

LoginWidget::LoginWidget(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("登录窗口");
    setFixedSize(400, 320);
    // 账户标签
    QLabel *labUser = new QLabel("账户:", this);
    labUser->setGeometry(40, 40, 60, 30);
    // 账户输入框
    QLineEdit *editUser = new QLineEdit(this);
    editUser->setGeometry(110, 40, 220, 30);
    // 密码标签
    QLabel *labPwd = new QLabel("口令:", this);
    labPwd->setGeometry(40, 90, 60, 30);
    // 密码输入框
    QLineEdit *editPwd = new QLineEdit(this);
    editPwd->setGeometry(110, 90, 220, 30);
    // 登录按钮
    QPushButton *btnLogin = new QPushButton("登录", this);
    btnLogin->setGeometry(240, 140, 90, 35);
}

知识点梳理

控件->setGeometry(x, y, width, height) x:距离窗口左上角横向坐标,y:纵向坐标;width/height:控件宽高。

致命缺陷: 坐标全部写死!如果取消setFixedSize允许窗口缩放,拉大窗口后,控件位置不会跟随自适应,界面直接错乱。

结论:正式项目禁止大量使用绝对定位,引出布局管理器。

版本5:布局管理器重构界面

新增知识点:Qt 四大布局、布局嵌套、QSpacerItem 弹簧 四大布局回顾:

  1. QVBoxLayout:垂直布局,自上而下排列
  2. QHBoxLayout:水平布局,自左向右排列
  3. QFormLayout:表单布局,适合【标签 + 输入框】表单
  4. QGridLayout:网格布局,行列表格形式

使用布局嵌套重构登录界面代码:

cpp 复制代码
#include "loginwidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QSpacerItem>

LoginWidget::LoginWidget(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("登录窗口");
    setFixedSize(400, 320);
    // 顶层垂直布局
    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    QFormLayout *formLayout = new QFormLayout();
    // 第一行:账户
    QHBoxLayout *line1 = new QHBoxLayout();
    line1->addWidget(new QLabel("账  户"));
    line1->addWidget(new QLineEdit());
    formLayout->addRow(line1);
    // 第二行:口令
    QHBoxLayout *line2 = new QHBoxLayout();
    line2->addWidget(new QLabel("口  令"));
    QLineEdit *pwdEdit = new QLineEdit();
    // 输入时明文,失去焦点隐藏密码
    pwdEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
    line2->addWidget(pwdEdit);
    formLayout->addRow(line2);
    // 第三行:弹簧 + 登录按钮
    QHBoxLayout *line3 = new QHBoxLayout();
    QSpacerItem *space = new QSpacerItem(200, 50);
    line3->addItem(space);
    line3->addWidget(new QPushButton("登录"));
    formLayout->addRow(line3);

    mainLayout->addLayout(formLayout);
    mainLayout->setAlignment(Qt::AlignCenter);
}

核心知识点

  1. 布局可以互相嵌套,实现复杂界面。
  2. QSpacerItem空白弹簧:填充空白区域,挤压控件实现对齐。
  3. 所有控件交给布局管理后,窗口缩放时控件自动适配位置。
  4. setEchoMode控制输入框密码显示模式。

版本6:引入 QSS 样式美化界面

当前界面控件样式默认原生,观感简陋,引入 QSS 美化。 新增知识点:Qt 样式表、原始字符串 R""、伪状态、样式优先级

最终完整代码:

cpp 复制代码
#include "loginwidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QSpacerItem>

LoginWidget::LoginWidget(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("登录窗口");
    setFixedSize(400, 320);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    QFormLayout *formLayout = new QFormLayout();

    QHBoxLayout *line1 = new QHBoxLayout();
    line1->addWidget(new QLabel("账  户"));
    line1->addWidget(new QLineEdit());
    formLayout->addRow(line1);

    QHBoxLayout *line2 = new QHBoxLayout();
    line2->addWidget(new QLabel("口  令"));
    QLineEdit *pwdEdit = new QLineEdit();
    pwdEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
    // 单个控件局部样式
    pwdEdit->setStyleSheet("color: blue;");
    line2->addWidget(pwdEdit);
    formLayout->addRow(line2);

    QHBoxLayout *line3 = new QHBoxLayout();
    QSpacerItem *space = new QSpacerItem(200, 50);
    line3->addItem(space);
    line3->addWidget(new QPushButton("登录"));
    formLayout->addRow(line3);

    mainLayout->addLayout(formLayout);
    mainLayout->setAlignment(Qt::AlignCenter);
    // 全局QSS样式
    QString qss=R"(
        *{
           font-size: 14px;
        }
        QLineEdit{
           font-size: 14px;
           padding: 5px;
           margin:  5px;
           border: 1px solid lightgray;
           border-radius: 10px;
        }
        QLineEdit:focus{
           border: 1px solid red;
        }
        QPushButton{
           padding: 20px 30px;
           background-color: lightblue;
           color: white;
        }
        QPushButton:hover{
            background-color: rgb(0,0,200);
        }
        QPushButton:pressed{
            background-color: green;
        }
        QLabel{
            color: green;
        }
    )";
    this->setStyleSheet(qss);
}

QSS 核心知识点

  1. R"(文本)":C++ 原始字符串,书写多行样式无需转义。
  2. 伪状态:

:focus:输入框获取光标焦点

:hover:鼠标悬浮控件上方

:pressed:鼠标按下控件

  1. 样式优先级:控件单独 setStyleSheet > 父窗口全局样式。
  2. 常用属性:border边框、border-radius圆角、padding内边距、background-color背景色。

三、全文知识点汇总

1. Qt GUI 程序生命周期

创建QApplication → 创建窗口控件 → show()显示 → a.exec()启动事件循环监听交互。

2. 信号与槽基础

QObject::connect实现事件绑定,Lambda 表达式可以充当槽函数。

3. 界面两种排版方案

  • 绝对定位setGeometry:简单、无法自适应,仅用于临时原型。
  • 四大布局管理器:支持自适应,支持嵌套,项目标准方案。

4. 内存管理

Qt 父子对象机制:父对象销毁时,自动释放所有子控件,一般无需手动 delete。

5. QSS 样式表

借鉴 CSS 语法美化控件,支持交互伪状态,区分全局样式与局部控件样式。

四、拓展练习任务

  1. 在登录界面增加【记住密码】复选框QCheckBox。
  2. 使用QGridLayout网格布局重新改造登录页面。
  3. 给下拉框QComboBox编写 QSS 圆角样式。
相关推荐
一只小灿灿1 小时前
C++ 各类特殊符号、运算符
开发语言·c++
Fu_Lin_1 小时前
《Qt嵌入式从零基础到精通》前言与阅读指南
开发语言·qt
名字还没想好☜1 小时前
Go 的 select 实战:超时、非阻塞收发与优雅退出的三个套路
开发语言·数据库·golang·go·并发
geovindu1 小时前
java: Backtracking Algorithm
java·开发语言·windows·后端·算法·回溯算法
晚风叙码2 小时前
C++ vector底层模拟实现与迭代器失效深度剖析
c++·算法
Scott9999HH10 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
2401_8414956410 小时前
【操作系统】进程同步与互斥实验报告
c++·算法·操作系统·进程·并发·同步·互斥
fqbqrr11 小时前
2607C++,soui与安卓
c++·soui
码智社11 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言