Qt

技术栈
工具链
qtc++gui跨平台桌面应用毕设

概览

Qt 技术栈概览

Qt 是由 Qt Company(原 Trolltech)开发的跨平台 C++ 应用程序框架,1995 年首次发布。以「Write once, compile anywhere」为理念,是 C++ GUI 开发的事实标准。

解决什么问题

  • 跨平台桌面应用:Windows / macOS / Linux 原生 GUI,一套代码三端运行
  • 嵌入式 HMI:工控触摸屏、车载中控、智能家居面板
  • 移动应用:Android / iOS 支持
  • 毕设上位机:串口调试工具、数据可视化仪表盘、物联网管理端

关键特性

  • 信号与槽:对象间通信机制,替代传统回调,类型安全
  • QML + Qt Quick:声明式 UI 开发,适合现代化界面
  • 丰富的控件库:按钮、表格、图表、树形控件等开箱即用
  • 跨平台一致:同一源码在不同平台编译,外观原生适配
  • Qt Creator IDE:集成开发环境,拖拽式 UI 设计器
  • 开源 LGPL 协议:免费用于商业/学术项目

安装

Qt 安装指南

1. 环境准备

要求 说明
操作系统 Windows 10+ / macOS 12+ / Linux (Ubuntu 20.04+)
编译器 MSVC 2019+ / GCC 8+ / Clang 10+
磁盘空间 Qt SDK 约 3-8 GB(含 Qt Creator)
内存 建议 8GB+

2. 安装命令

Windows / macOS — Qt Online Installer(推荐)

  1. 访问 qt.io/download
  2. 下载 Qt Online Installer
  3. 安装时勾选所需版本(推荐 Qt 6.6 LTS)
  4. 选择组件:勾选 MSVC 2019 64-bitMinGW,以及 Qt Creator

macOS (Homebrew,轻量)

brew install qt@6
echo 'export PATH="/opt/homebrew/opt/qt@6/bin:$PATH"' >;> ~/.zshrc

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install -y qt6-base-dev qt6-tools-dev qt6-tools-dev-tools
sudo apt install -y qtcreator          # Qt Creator IDE

验证安装

qmake --version
# 或 cmake 方式
cmake --version

3. 常见安装问题

问题 解决方案
Qt Online Installer 下载慢 使用国内镜像(清华、中科大),或离线安装包
CMake 找不到 Qt 设置 CMAKE_PREFIX_PATH 指向 Qt 安装路径
Linux 缺少 OpenGL sudo apt install libgl1-mesa-dev
编译报 MOC 错误 确保 .h 文件中 Q_OBJECT 宏的类被 MOC 处理
Qt5 和 Qt6 并存冲突 使用 CMake 的 find_package(Qt6) 明确版本

示例

Qt 信号与槽——温度转换器

目标

演示 Qt 核心机制「信号与槽」:一个摄氏/华氏温度互转的小工具,输入即实时转换。

完整代码

main.cpp

#include <QApplication>
#include "TemperatureConverter.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    TemperatureConverter window;
    window.setWindowTitle("温度转换器 - Qt 示例");
    window.resize(350, 150);
    window.show();

    return app.exec();
}

TemperatureConverter.h

#ifndef TEMPERATURECONVERTER_H
#define TEMPERATURECONVERTER_H

#include <QWidget>
#include <QLineEdit>
#include <QLabel>

class TemperatureConverter : public QWidget {
    Q_OBJECT

public:
    explicit TemperatureConverter(QWidget *parent = nullptr);

private slots:
    void onCelsiusChanged(const QString &text);
    void onFahrenheitChanged(const QString &text);

private:
    QLineEdit *celsiusInput;
    QLineEdit *fahrenheitInput;
    QLabel *statusLabel;
    bool updating = false;  // 防止信号循环
};

#endif

TemperatureConverter.cpp

#include "TemperatureConverter.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDoubleValidator>

TemperatureConverter::TemperatureConverter(QWidget *parent)
    : QWidget(parent) {

    // 输入验证器:只允许数字
    auto *validator = new QDoubleValidator(-273.15, 10000, 2, this);

    celsiusInput = new QLineEdit(this);
    celsiusInput->setPlaceholderText("摄氏度");
    celsiusInput->setValidator(validator);

    fahrenheitInput = new QLineEdit(this);
    fahrenheitInput->setPlaceholderText("华氏度");
    fahrenheitInput->setValidator(validator);

    statusLabel = new QLabel("请在上面输入温度", this);

    // 布局
    auto *mainLayout = new QVBoxLayout(this);
    auto *inputLayout = new QHBoxLayout();
    inputLayout->addWidget(new QLabel("°C:"));
    inputLayout->addWidget(celsiusInput);
    inputLayout->addWidget(new QLabel("°F:"));
    inputLayout->addWidget(fahrenheitInput);
    mainLayout->addLayout(inputLayout);
    mainLayout->addWidget(statusLabel);

    // --- 信号与槽:Qt 的核心通信机制 ---
    connect(celsiusInput, &QLineEdit::textChanged,
            this, &TemperatureConverter::onCelsiusChanged);
    connect(fahrenheitInput, &QLineEdit::textChanged,
            this, &TemperatureConverter::onFahrenheitChanged);
}

void TemperatureConverter::onCelsiusChanged(const QString &text) {
    if (updating) return;
    bool ok;
    double c = text.toDouble(&ok);
    if (!ok || text.isEmpty()) {
        statusLabel->setText("请输入有效数字");
        return;
    }
    double f = c * 9.0 / 5.0 + 32;
    updating = true;
    fahrenheitInput->setText(QString::number(f, 'f', 2));
    updating = false;
    statusLabel->setText(QString("%1°C = %2°F").arg(c).arg(f, 0, 'f', 2));
}

void TemperatureConverter::onFahrenheitChanged(const QString &text) {
    if (updating) return;
    bool ok;
    double f = text.toDouble(&ok);
    if (!ok || text.isEmpty()) {
        statusLabel->setText("请输入有效数字");
        return;
    }
    double c = (f - 32) * 5.0 / 9.0;
    updating = true;
    celsiusInput->setText(QString::number(c, 'f', 2));
    updating = false;
    statusLabel->setText(QString("%1°F = %2°C").arg(f).arg(c, 0, 'f', 2));
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(TemperatureConverter LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)       # 关键:自动处理 Q_OBJECT 宏

find_package(Qt6 REQUIRED COMPONENTS Widgets)

add_executable(${PROJECT_NAME}
    main.cpp
    TemperatureConverter.cpp
)

target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets)

运行步骤

mkdir build &;& cd build
cmake ..
make -j$(nproc)
./TemperatureConverter

关键点

  • 信号与槽是 Qt 最核心的设计:connect(sender, SIGNAL, receiver, SLOT)
  • CMAKE_AUTOMOC ON 自动处理 Q_OBJECT 宏,必须开启
  • updating 标志防止两个输入框互相触发形成无限循环
  • QDoubleValidator 限制输入为合法数值

教程

Qt 毕设入门教程——上位机开发指南

前言

Qt 是毕设上位机开发的首选框架。常见场景:串口调试助手、温湿度监控面板、数据可视化大屏、智能家居控制端


第一章:Qt 核心概念速通

信号与槽

Qt 最核心的通信机制,替代传统回调函数:

// 按钮点击 → 执行函数
connect(btnSave, &QPushButton::clicked, this, &MyWidget::onSave);
  • 信号:事件发生时自动发射(如按钮点击、数据到达)
  • :响应信号的普通成员函数
  • 连接connect(发送者, 信号, 接收者, 槽)

父子对象模型

Qt 自动管理内存:父对象销毁时自动销毁子对象,无需手动 delete


第二章:实战——串口调试助手

这是毕设中最常见的上位机项目。

关键类

#include <QSerialPort>
#include <QSerialPortInfo>

扫描可用串口

auto ports = QSerialPortInfo::availablePorts();
for (const auto& port : ports) {
    qDebug() << port.portName() << port.description();
}

打开串口

QSerialPort serial;
serial.setPortName("COM3");        // Windows
// serial.setPortName("/dev/ttyUSB0"); // Linux
serial.setBaudRate(QSerialPort::Baud115200);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);

if (serial.open(QIODevice::ReadWrite)) {
    connect(&serial, &QSerialPort::readyRead, [&]() {
        QByteArray data = serial.readAll();
        qDebug() << "收到:" << data;
    });
}

发送数据

serial.write("Hello MCU\r\n");

第三章:数据可视化——QChart

# CMakeLists.txt 需添加
find_package(Qt6 REQUIRED COMPONENTS Charts)
target_link_libraries(... PRIVATE Qt6::Charts)

实时折线图示例

#include <QtCharts>

auto *series = new QLineSeries();
auto *chart = new QChart();
chart->addSeries(series);
chart->createDefaultAxes();
chart->setTitle("温度实时曲线");

auto *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);

// 每秒添加一个数据点
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, [series, &sensor]() {
    static int t = 0;
    series->append(t++, sensor.readTemperature());
});
timer->start(1000);

第四章:打包发布

Windows 打包

# 在 exe 所在目录
windeployqt MyApp.exe
# 自动复制所需 DLL,可直接发给导师

macOS 打包

macdeployqt MyApp.app -dmg

第五章:常见踩坑

问题 解决
UI 卡顿 耗时操作放子线程 QThreadQtConcurrent
中文乱码 源文件 UTF-8 BOM,或 QStringLiteral()
信号未触发 检查是否 connect 成功(返回值)
Q_OBJECT 报错 确保头文件被 MOC 处理,CMake 开启 CMAKE_AUTOMOC ON

思考题

  1. 如何实现串口接收数据后实时更新图表?
  2. QThreadQtConcurrent::run 的区别是什么?
  3. 如何用 Qt 实现 Modbus RTU/TCP 通信?

参考资料

  1. [1] Qt Company. Qt Documentation. 2024. https://doc.qt.io/
  2. [2] Jasmin Blanchette, Mark Summerfield. C++ GUI Programming with Qt 4. 2008.
  3. [3] Lee Zhi Eng. Qt 5 and C++ Programming Cookbook. 2019.