Note

本篇逐一讲解 Qt 中最常用的 11 个控件:显示类(QLabel、QProgressBar、QGroupBox)、按钮类(QPushButton、QCheckBox、QRadioButton)、输入类(QLineEdit、QTextEdit、QComboBox、QSpinBox、QSlider)。每个控件按”是什么→怎么用”展开,并附可编译的完整示例。适合刚装好 Qt Creator、写过 Hello World 的初学者。

控件家族的共同底座:QWidget

在认识各个控件之前,先要明白一件事:所有控件都直接或间接继承自 QWidget。QWidget 提供了位置、大小、字体、提示、鼠标光标等通用属性,所以任何控件都有 setToolTip()setFont()setFixedSize() 这些方法。

更重要的机制是父子关系:构造控件时传入父对象指针,控件就会显示在父窗口内部,并在父窗口销毁时自动销毁——你几乎不需要手写 delete

Warning

如果用 new 创建控件却没传父对象,Qt 不会帮你回收,必须自己管理内存,否则就是内存泄漏。养成习惯:控件创建时就把 this 传进去。

QLabel:显示文本与图片

QLabel 是最基础的显示控件,不接收输入,可以显示纯文本、富文本(HTML)、图片(QPixmap)、动态图(QMovie)。

QLabel *label = new QLabel(this);
label->setText("用户名:");          // 显示文本
label->setAlignment(Qt::AlignCenter); // 居中对齐,可用 | 组合多方向
label->setPixmap(QPixmap(":/logo.png")); // 显示图片(来自资源文件)

适用场景:标题、说明文字、字段名(配合输入框)、图片预览。它还有个隐藏技能——setBuddy() 设置”伙伴”控件后,用户按下标签文本里 & 指定的快捷键(如 &N 对应 Alt+N),焦点会自动跳到伙伴输入框上。

QPushButton:点击触发动作

QPushButton 是最常见的按钮,核心是 clicked() 信号。它支持文本、图标、工具提示三种配置:

QPushButton *btn = new QPushButton("打开文件", this);
btn->setIcon(QIcon(":/open.png"));
btn->setToolTip("选择一个文件打开");
connect(btn, &QPushButton::clicked, this, &MainWindow::openFile);

适用场景:确认、取消、打开、提交等一次性动作。clicked(bool checked) 的参数对普通按钮没什么用——它按下即弹起,没有”按住”状态。

QLineEdit:单行文本输入

QLineEdit 接收一行文本,自带复制、粘贴、撤销、重做等编辑功能。核心属性是 text

QLineEdit *edit = new QLineEdit(this);
edit->setPlaceholderText("请输入用户名");      // 灰色提示文字
edit->setMaxLength(20);                        // 限制最大长度
connect(edit, &QLineEdit::textChanged, this, &MainWindow::onTextChanged);

密码框是它的经典用法,通过回显模式(echoMode)切换:

QLineEdit *pwd = new QLineEdit(this);
pwd->setEchoMode(QLineEdit::Password);   // 输入内容显示为 *

常用信号:textChanged(任何原因导致的文本变化都触发)、textEdited(仅用户手动编辑触发)、returnPressed(按下回车)、editingFinished(回车或失去焦点)。需要校验输入时挂一个验证器,非法字符根本输不进去:

// 只允许输入 0~65535 的整数
edit->setValidator(new QIntValidator(0, 65535, edit));

QTextEdit:多行富文本编辑

QTextEdit 支持多行文本和 HTML 富文本编辑;只读场景用它的子类 QTextBrowser(还能打开链接)。需要纯文本(无格式、占用小)时,QPlainTextEdit 更合适。

QTextEdit *editor = new QTextEdit(this);
editor->setPlainText("初始内容");        // 按纯文本设置
editor->setHtml("<b>加粗</b>内容");      // 按 HTML 设置
QString text = editor->toPlainText();    // 取出纯文本

适用场景:留言板、日志显示、笔记编辑器。取内容时注意选对 toPlainText() 还是 toHtml()

QCheckBox:多选项与三态

QCheckBox 表示可以多个同时勾选的开关选项,核心是 isChecked()toggled(bool) 信号(状态翻转时触发)。

QCheckBox *cb = new QCheckBox("记住密码", this);
connect(cb, &QCheckBox::toggled, this, [](bool on){
    qDebug() << "记住密码:" << on;
});

开启 setTristate(true) 后变成三态:未选中 / 部分选中 / 全选中,状态用 checkState() 读取。“全选”复选框就是典型应用——子项全选时它是选中态,部分选中时它自动显示半选态。

QRadioButton:单选互斥

QRadioButton 用于一组中只能选一个的场景。同一父窗口(或同一个分组容器)里的单选按钮自动互斥:选中新的,旧的自动取消。

// 同一 QGroupBox 内的两个单选按钮天然互斥
QGroupBox *box = new QGroupBox("性别", this);
QRadioButton *male = new QRadioButton("男");
QRadioButton *female = new QRadioButton("女");
female->setChecked(true);   // 设置默认选中

Warning

互斥只对”同一个父容器”内的单选按钮生效。如果性别和年龄段的单选按钮都直接放在窗体上,它们会互相干扰——点性别会把年龄段的选中清掉。解决方法:要么分别放进不同的 QGroupBox,要么用 QButtonGroup 在内存里做虚拟分组。

QComboBox:下拉选择

QComboBox 是”单行编辑框 + 下拉列表”的组合,用户可以点选,可编辑模式下还能手动输入。条目可以携带隐藏的自定义数据:

QComboBox *combo = new QComboBox(this);
combo->addItem("米饭", 5.0);      // 第二个参数是隐藏数据(单价)
combo->addItems({"面条", "饺子"}); // 批量添加
combo->setEditable(true);          // 允许用户输入新条目
 
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
        this, [this](int i){ qDebug() << "选中" << combo->itemData(i); });

itemData() 取出的隐藏数据,比”根据序号再查表”的写法干净得多。常用信号是 currentIndexChanged(int)(序号变)和 currentTextChanged(QString)(文本变)。

QSpinBox / QSlider:数值输入的两种姿势

QSpinBox(微调框)是”整数编辑框 + 上下箭头”,适合精确输入;QSlider(滑动条)是拖动的滑块,适合模糊地连续调整。两者都继承自整数值体系,用信号槽可以轻松联动:

QSpinBox *spin = new QSpinBox(this);
spin->setRange(0, 100);
spin->setSuffix(" %");           // 数值后自动带单位
 
QSlider *slider = new QSlider(Qt::Horizontal, this);
slider->setRange(0, 100);
 
// 双向联动:拖滑块改数字,改数字动滑块
connect(spin, QOverload<int>::of(&QSpinBox::valueChanged),
        slider, &QSlider::setValue);
connect(slider, &QSlider::valueChanged,
        spin, &QSpinBox::setValue);

Success

不用担心双向 connect 造成死循环:Qt 的 setValue() 发现新值与当前值相同会直接返回,不再发信号。音量调节、缩放比例这类”数字 + 滑块”界面就是标准写法。

QSlider 还可以用 setTickPosition(QSlider::TicksBelow)setTickInterval(10) 显示刻度。处理浮点数时换用 QDoubleSpinBox(多了 setDecimals() 控制小数位数)。

QProgressBar:进度展示

QProgressBar 显示任务完成比例,不接收用户输入,只被代码驱动:

QProgressBar *bar = new QProgressBar(this);
bar->setRange(0, 100);
bar->setValue(40);
bar->setFormat("%v / %m");   // 自定义文本格式:40 / 100

显示文本由范围与当前值自动算出,占位符 %p 是百分比、%v 是当前值、%m 是上限减下限。它的绝配是 QSlider——官方教程里”滑块拖动、进度条同步”就是一行 connect 完成的。

QGroupBox:分组容器

QGroupBox 是带标题和边框的容器,本身不处理业务,价值在于视觉分组逻辑分组:一组单选按钮放进一个 QGroupBox,既明确了归属,又天然实现了组内互斥。

QGroupBox *box = new QGroupBox("字体样式", this);
QCheckBox *bold   = new QCheckBox("加粗");
QCheckBox *italic = new QCheckBox("斜体");
QVBoxLayout *lay = new QVBoxLayout(box);  // 布局器以 box 为父
lay->addWidget(bold);
lay->addWidget(italic);

Success

给容器控件设置布局时,直接 new QVBoxLayout(box) 就等于完成了”建布局 + setLayout”两步。往组框里塞控件时注意始终通过布局器排布,别用固定坐标。

控件速查表

控件用途常用信号
QLabel显示文本/图片linkActivated
QPushButton触发动作clicked
QLineEdit单行输入textChanged、returnPressed
QTextEdit多行富文本编辑textChanged
QCheckBox多选开关toggled、stateChanged
QRadioButton组内单选toggled
QComboBox下拉选择currentIndexChanged
QSpinBox整数微调输入valueChanged
QSlider连续数值调节valueChanged
QProgressBar进度展示valueChanged
QGroupBox分组容器

完整可运行示例

下面把以上控件拼在一个窗口里,Qt5 / Qt6 均可编译:

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QCheckBox>
#include <QRadioButton>
#include <QComboBox>
#include <QSpinBox>
#include <QSlider>
#include <QProgressBar>
#include <QGroupBox>
#include <QVBoxLayout>
#include <QFormLayout>
#include <QDebug>
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QWidget window;
    window.setWindowTitle("常用控件示例");
    window.resize(420, 480);
 
    // 标签:提示文字
    QLabel *label = new QLabel("下面是一个简单的设置表单:");
 
    // 单行输入:用户名,限制 20 字符
    QLineEdit *nameEdit = new QLineEdit;
    nameEdit->setPlaceholderText("请输入用户名");
    nameEdit->setMaxLength(20);
 
    // 密码框:回显模式显示为 *
    QLineEdit *pwdEdit = new QLineEdit;
    pwdEdit->setEchoMode(QLineEdit::Password);
 
    // 下拉框:选择城市,条目携带隐藏数据(区号)
    QComboBox *cityCombo = new QComboBox;
    cityCombo->addItem("北京", "010");
    cityCombo->addItem("上海", "021");
 
    // 单选按钮:放在同一分组框内自动互斥
    QGroupBox *genderBox = new QGroupBox("性别");
    QRadioButton *male = new QRadioButton("男");
    QRadioButton *female = new QRadioButton("女");
    female->setChecked(true);
    QVBoxLayout *genderLay = new QVBoxLayout(genderBox);
    genderLay->addWidget(male);
    genderLay->addWidget(female);
 
    // 复选框:三选三不互斥
    QCheckBox *agree = new QCheckBox("我已阅读并同意用户协议");
 
    // 数值输入与滑块联动:0~100
    QSpinBox *spin = new QSpinBox;
    spin->setRange(0, 100);
    QSlider *slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, 100);
    connect(spin, QOverload<int>::of(&QSpinBox::valueChanged),
            slider, &QSlider::setValue);
    connect(slider, &QSlider::valueChanged,
            spin, &QSpinBox::setValue);
 
    // 进度条跟随滑块
    QProgressBar *bar = new QProgressBar;
    bar->setRange(0, 100);
    connect(slider, &QSlider::valueChanged,
            bar, &QProgressBar::setValue);
 
    // 多行编辑
    QTextEdit *editor = new QTextEdit;
    editor->setPlaceholderText("备注信息(可多行)");
 
    // 按钮
    QPushButton *btn = new QPushButton("提交");
    connect(btn, &QPushButton::clicked, [nameEdit, pwdEdit, cityCombo, agree, spin](){
        if (!agree->isChecked()) {
            qDebug() << "请先勾选协议";
            return;
        }
        qDebug() << "提交:" << nameEdit->text()
                 << cityCombo->currentText()
                 << "透明度" << spin->value() << "%";
    });
 
    // 表单布局:左列标签、右列输入控件
    QFormLayout *form = new QFormLayout;
    form->addRow("用户名", nameEdit);
    form->addRow("密码", pwdEdit);
    form->addRow("城市", cityCombo);
 
    // 垂直主布局把所有内容从上到下排好
    QVBoxLayout *mainLay = new QVBoxLayout(&window);
    mainLay->addWidget(label);
    mainLay->addLayout(form);
    mainLay->addWidget(genderBox);
    mainLay->addWidget(agree);
    mainLay->addWidget(spin);
    mainLay->addWidget(slider);
    mainLay->addWidget(bar);
    mainLay->addWidget(editor);
    mainLay->addWidget(btn);
 
    window.show();
    return app.exec();
}

Success

记控件不必死记硬背:先记住 QWidget 这个共同基类,再按”显示 / 按钮 / 输入 / 容器”四类归类理解。真正写项目时,Qt 助手(Qt Creator 里按 F1)随时能查到每个控件的全部方法与信号。