Qt 实战指南

FreeGuideOnline 最新 2026-07-16

bash sudo apt update sudo apt install qt6-base-dev qt6-tools-dev qt6-tools-dev-tools qtcreator


### 1.3 验证环境

打开 Qt Creator,创建新项目:
- 选择 `Application (Qt Widgets)` 模板
- 选择编译套件(Kit),点击运行(绿色三角形)

如果出现空白窗口,则环境就绪。

## 第 2 章:第一个 Qt 窗口程序

### 2.1 手动编写一个简单窗口

创建一个纯文本的 C++ 源文件 `main.cpp`,代码:
```cpp
#include <QApplication>
#include <QLabel>

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

    QLabel label("Hello, Qt 6!");
    label.setWindowTitle("我的第一个程序");
    label.resize(300, 200);
    label.show();

    return app.exec();
}

使用 qmake 或 Qt Creator 构建项目。运行后会看到一个显示文字的窗口。

2.2 项目结构剖析

一般的 Qt Widgets 项目包含:

  • .pro 文件:工程文件,定义源文件、头文件和模块依赖
  • main.cpp:程序入口
  • 类通常继承自 QWidget 或其子类,用于搭建界面

示例 .pro 文件:

QT       += core gui widgets
TARGET = MyApp
SOURCES += main.cpp
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

2.3 信号与槽初探

信号与槽是 Qt 的核心机制。对象可以发出信号,槽是普通函数,响应信号。

下面是一个按钮点击关闭窗口的例子:

#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QPushButton button("退出");
    QObject::connect(&button, &QPushButton::clicked, &app, &QApplication::quit);
    button.show();
    return app.exec();
}
  • clicked 是按钮的信号
  • quitQApplication 的槽
  • 当按钮被点击,应用程序退出

第 3 章:常用控件与布局

3.1 基本控件速览

控件 类名 作用
按钮 QPushButton 带文字的普通按钮
标签 QLabel 显示文本或图片
单行输入 QLineEdit 单行文本输入框
多行输入 QTextEdit 富文本/多行文本编辑
复选框 QCheckBox 多选开关
单选按钮 QRadioButton 互斥选择(配合 QButtonGroup
组合框 QComboBox 下拉列表选择
滑块 QSlider 拖拽取值
进度条 QProgressBar 进度显示

3.2 布局管理器

不使用绝对坐标,用布局管理器自动调整控件位置和大小。

常用布局:

  • QHBoxLayout:水平排列
  • QVBoxLayout:垂直排列
  • QGridLayout:表格网格排列
  • QFormLayout:两列标签-字段表单布局

示例:使用垂直布局放置标签和按钮

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget window;
    window.setWindowTitle("布局示例");

    QLabel *label = new QLabel("用户名:");
    QPushButton *btn = new QPushButton("登录");

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(label);
    layout->addWidget(btn);

    window.setLayout(layout);
    window.show();
    return app.exec();
}

第 4 章:深入信号与槽

4.1 自定义槽函数

创建自己的窗口类,继承自 QWidget,添加槽函数。

头文件 MyWidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
#include <QPushButton>

class MyWidget : public QWidget
{
    Q_OBJECT
public:
    MyWidget(QWidget *parent = nullptr);
private slots:
    void onButtonClicked();
private:
    QPushButton *m_button;
};

#endif

源文件 MyWidget.cpp

#include "MyWidget.h"
#include <QMessageBox>

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
    m_button = new QPushButton("点我", this);
    connect(m_button, &QPushButton::clicked, this, &MyWidget::onButtonClicked);
}

void MyWidget::onButtonClicked()
{
    QMessageBox::information(this, "提示", "按钮被点击了!");
}

4.2 带参数的信号传递

许多控件信号携带参数,例如 QLineEdit::textChanged(const QString &text)

QLineEdit *edit = new QLineEdit;
QObject::connect(edit, &QLineEdit::textChanged, [](const QString &text){
    qDebug() << "当前输入:" << text;
});

使用 Lambda 表达式作为槽,简洁方便(C++11 起支持)。

4.3 自定义信号

在类中声明 signals: 区域:

signals:
    void valueChanged(int newValue);

发射信号:emit valueChanged(100);

第 5 章:实战项目——简易计算器

5.1 需求与界面设计

制作一个能进行加减乘除的桌面计算器,界面包含:

  • 一个 QLineEdit 显示表达式和结果
  • 数字按钮 0-9
  • 运算符按钮 + - * /
  • 等于按钮 =,清除按钮 C

布局采用 QGridLayout,将按钮放在网格中。

5.2 核心逻辑设计

  • 需要存储当前输入的第一个操作数、等待的运算符、以及是否正在输入第二个操作数。
  • 点击数字按钮:追加数字到当前输入,更新显示。
  • 点击运算符:保存第一个操作数和运算符,清空输入框准备下一个数。
  • 点击等号:根据保存的运算符计算,显示结果。

5.3 完整代码实现

Calculator.h

#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <QWidget>
#include <QLineEdit>
#include <QPushButton>

class Calculator : public QWidget
{
    Q_OBJECT
public:
    explicit Calculator(QWidget *parent = nullptr);
private slots:
    void digitClicked();
    void operatorClicked();
    void equalsClicked();
    void clear();
private:
    void createLayout();
    QPushButton* createButton(const QString &text, const char *slot);

    QLineEdit *display;
    double pending_value = 0;
    QString pending_operator;
    bool waiting_for_operand = true;
};

#endif

Calculator.cpp

#include "Calculator.h"
#include <QGridLayout>
#include <QVector>

Calculator::Calculator(QWidget *parent) : QWidget(parent)
{
    display = new QLineEdit("0");
    display->setReadOnly(true);
    display->setAlignment(Qt::AlignRight);
    display->setMaxLength(15);

    createLayout();
}

void Calculator::createLayout()
{
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(display, 0, 0, 1, 4);

    const QVector<QString> buttons = {
        "7", "8", "9", "/",
        "4", "5", "6", "*",
        "1", "2", "3", "-",
        "0", ".", "C", "+",
        "="
    };

    int row = 1, col = 0;
    for (const QString &text : buttons) {
        QPushButton *button = new QPushButton(text);
        if (text == "C") {
            connect(button, &QPushButton::clicked, this, &Calculator::clear);
        } else if (text == "=") {
            layout->addWidget(button, row, col, 1, 4); // 等号跨4列
            connect(button, &QPushButton::clicked, this, &Calculator::equalsClicked);
            break;
        } else if (text == "+" || text == "-" || text == "*" || text == "/") {
            connect(button, &QPushButton::clicked, this, &Calculator::operatorClicked);
        } else {
            connect(button, &QPushButton::clicked, this, &Calculator::digitClicked);
        }

        layout->addWidget(button, row, col);
        col++;
        if (col > 3) {
            col = 0;
            row++;
        }
    }

    setLayout(layout);
    setWindowTitle("简易计算器");
}

void Calculator::digitClicked()
{
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
    QString digit = btn->text();

    if (waiting_for_operand) {
        display->clear();
        waiting_for_operand = false;
    }

    if (display->text() == "0" && digit == "0")
        return; // 避免多个零

    if (display->text() == "0" && digit != ".")
        display->setText(digit);
    else
        display->setText(display->text() + digit);
}

void Calculator::operatorClicked()
{
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
    QString op = btn->text();

    if (!waiting_for_operand) {
        // 如果之前有输入,则先计算一下
        if (!pending_operator.isEmpty())
            equalsClicked();
        pending_value = display->text().toDouble();
        pending_operator = op;
        waiting_for_operand = true;
    } else {
        // 连续点击运算符时更新运算符
        pending_operator = op;
    }
}

void Calculator::equalsClicked()
{
    if (waiting_for_operand)
        return;

    double right = display->text().toDouble();
    double result = 0;
    if (pending_operator == "+")
        result = pending_value + right;
    else if (pending_operator == "-")
        result = pending_value - right;
    else if (pending_operator == "*")
        result = pending_value * right;
    else if (pending_operator == "/") {
        if (right == 0) {
            display->setText("错误");
            pending_value = 0;
            pending_operator.clear();
            waiting_for_operand = true;
            return;
        }
        result = pending_value / right;
    } else {
        return;
    }

    display->setText(QString::number(result));
    pending_value = result;
    pending_operator.clear();
    waiting_for_operand = true;
}

void Calculator::clear()
{
    display->setText("0");
    pending_value = 0;
    pending_operator.clear();
    waiting_for_operand = true;
}

main.cpp

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

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Calculator calc;
    calc.show();
    return app.exec();
}