基础控件
Qt Widgets 提供了丰富的桌面控件,本节深入介绍最常用的基础控件及其用法。理解这些控件的工作原理和使用技巧,是构建专业桌面应用的基础。
控件的共同特性
Qt 的所有控件都继承自 QWidget,这意味着它们拥有一些共同的属性和行为。理解这些共同特性有助于快速掌握各类控件的使用方法。
基础属性操作
每个控件都具备以下核心属性:
// 启用与禁用
widget->setEnabled(false); // 禁用控件(变灰,不响应交互)
widget->setEnabled(true); // 重新启用
bool isDisabled = widget->isEnabled(); // 检查状态
// 可见性控制
widget->setVisible(true); // 显示控件
widget->setVisible(false); // 隐藏控件
widget->hide(); // 隐藏(等效于 setVisible(false))
widget->show(); // 显示(等效于 setVisible(true))
bool isVisible = widget->isVisible();
// 窗口标题(对顶层窗口有效)
widget->setWindowTitle("应用程序标题");
// 几何属性
widget->resize(400, 300); // 设置大小
widget->setFixedSize(400, 300); // 固定大小(不可拖拽调整)
widget->move(100, 100); // 设置位置(屏幕坐标)
widget->setGeometry(100, 100, 400, 300); // 同时设置位置和大小
// 样式表
widget->setStyleSheet("color: red; background: white;");
// 工具提示
widget->setToolTip("这是提示信息");
控件的父子关系
Qt 使用对象树管理控件的内存和层次结构:
// 创建控件时指定父对象
QPushButton *button = new QPushButton("按钮", parentWidget);
// 父对象销毁时,子控件会自动销毁
// 因此通常不需要手动 delete 子控件
// 获取父控件
QWidget *parent = button->parentWidget();
// 获取所有子控件
QList<QWidget*> children = parentWidget->findChildren<QWidget*>();
QLabel(标签)
QLabel 是最简单的控件,用于显示文本、图片或动画。它不接收键盘焦点,适合作为信息展示区域。
基本文本显示
#include <QLabel>
// 创建标签
QLabel *label = new QLabel("Hello Qt", this);
// 设置文本内容
label->setText("新文本内容");
// 获取文本
QString text = label->text();
// 文本对齐方式
label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); // 左对齐+垂直居中
label->setAlignment(Qt::AlignCenter); // 完全居中
label->setAlignment(Qt::AlignRight | Qt::AlignTop); // 右上对齐
// 自动换行
label->setWordWrap(true); // 启用自动换行
label->setWordWrap(false); // 禁用自动换行(默认)
文本对齐选项详解:
| 对齐标志 | 说明 |
|---|---|
Qt::AlignLeft | 水平左对齐 |
Qt::AlignRight | 水平右对齐 |
Qt::AlignHCenter | 水平居中 |
Qt::AlignTop | 垂直顶部对齐 |
Qt::AlignBottom | 垂直底部对齐 |
Qt::AlignVCenter | 垂直居中 |
Qt::AlignCenter | 水平和垂直同时居中 |
富文本支持
QLabel 支持 HTML 子集,可以显示富文本:
// HTML 富文本
QLabel *htmlLabel = new QLabel(this);
htmlLabel->setText("<h1>标题</h1>"
"<p style='color:red;'>红色段落文字</p>"
"<ul><li>列表项1</li><li>列表项2</li></ul>");
// 设置文本格式
htmlLabel->setTextFormat(Qt::RichText); // 富文本模式(默认)
htmlLabel->setTextFormat(Qt::PlainText); // 纯文本模式
htmlLabel->setTextFormat(Qt::AutoText); // 自动检测
// 常用 HTML 标签
QString richText = R"(
<b>粗体</b> <i>斜体</i> <u>下划线</u>
<span style="color:#FF0000;">红色文字</span>
<a href="https://qt.io">链接</a>
)";
图片显示
// 显示图片
QLabel *imageLabel = new QLabel(this);
imageLabel->setPixmap(QPixmap(":/images/logo.png"));
// 图片缩放(保持比例)
QPixmap pixmap(":/images/photo.jpg");
QPixmap scaled = pixmap.scaled(200, 150, Qt::KeepAspectRatio, Qt::SmoothTransformation);
imageLabel->setPixmap(scaled);
// 图片自适应标签大小
imageLabel->setScaledContents(true); // 图片会拉伸填充标签
// 注意:可能导致图片变形
// 推荐做法:固定标签大小,图片保持比例
imageLabel->setFixedSize(200, 150);
imageLabel->setPixmap(pixmap.scaled(imageLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
交互式标签
虽然 QLabel 主要用于显示,但也可以添加简单的交互:
// 启用文本选择
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
// 用户可以用鼠标选择和复制文本
// 启用链接点击
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
label->setOpenExternalLinks(true); // 自动打开外部链接
// 连接链接点击信号
connect(label, &QLabel::linkActivated, this, [](const QString &link) {
qDebug() << "点击了链接:" << link;
});
// 示例:带链接的标签
label->setText("访问 <a href='https://qt.io'>Qt官网</a> 获取更多信息");
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
label->setOpenExternalLinks(true);
QPushButton(按钮)
QPushButton 是最常用的交互控件,用于触发操作。它支持普通按钮、切换按钮、菜单按钮等多种形式。
基本用法
#include <QPushButton>
// 创建按钮
QPushButton *button = new QPushButton("点击我", this);
// 获取和设置文本
button->setText("新文本");
QString text = button->text();
// 设置大小
button->setFixedSize(120, 40); // 固定大小
button->setMinimumSize(100, 30); // 最小大小
// 设置图标
button->setIcon(QIcon(":/icons/save.png"));
button->setIconSize(QSize(24, 24));
// 设置快捷键
button->setShortcut(QKeySequence("Ctrl+S"));
button->setShortcut(Qt::Key_Enter); // 单键快捷键
点击事件处理
按钮的核心功能是响应点击事件,Qt 提供了多种处理方式:
// 方式一:连接 clicked 信号(推荐)
connect(button, &QPushButton::clicked, this, []() {
qDebug() << "按钮被点击";
});
// 方式二:Lambda 捕获上下文
QPushButton *btn1 = new QPushButton("按钮1");
QPushButton *btn2 = new QPushButton("按钮2");
connect(btn1, &QPushButton::clicked, this, [this, btn1]() {
// 可以访问 this 和 btn1
handleButtonClick(btn1->text());
});
// 方式三:连接到槽函数
// 在类声明中
class MainWindow : public QMainWindow {
Q_OBJECT
private slots:
void onButtonClicked();
};
// 在类实现中
void MainWindow::onButtonClicked() {
// 处理点击
}
// 连接
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
切换按钮
QPushButton 可以作为切换按钮使用,用于开关类操作:
// 设置为可切换
QPushButton *toggleBtn = new QPushButton("开关", this);
toggleBtn->setCheckable(true); // 启用切换功能
// 设置初始状态
toggleBtn->setChecked(true); // 初始为选中状态
// 监听状态变化
connect(toggleBtn, &QPushButton::toggled, this, [](bool checked) {
if (checked) {
qDebug() << "开关打开";
} else {
qDebug() << "开关关闭";
}
});
// 实际应用:显示/隐藏面板
QPushButton *panelToggle = new QPushButton("显示面板");
panelToggle->setCheckable(true);
panelToggle->setChecked(true);
QWidget *panel = new QWidget;
connect(panelToggle, &QPushButton::toggled, panel, &QWidget::setVisible);
按钮样式定制
使用样式表可以完全自定义按钮外观:
button->setStyleSheet(R"(
QPushButton {
background-color: #4CAF50; /* 背景色 */
color: white; /* 文字颜色 */
border: none; /* 无边框 */
padding: 10px 20px; /* 内边距 */
border-radius: 4px; /* 圆角 */
font-size: 14px; /* 字号 */
font-weight: bold; /* 粗体 */
}
QPushButton:hover {
background-color: #45a049; /* 悬停颜色 */
}
QPushButton:pressed {
background-color: #3d8b40; /* 按下颜色 */
}
QPushButton:disabled {
background-color: #cccccc; /* 禁用颜色 */
color: #666666;
}
)");
带菜单的按钮
按钮可以关联下拉菜单:
#include <QMenu>
QPushButton *menuBtn = new QPushButton("选项", this);
menuBtn->setIcon(QIcon(":/icons/arrow-down.png"));
QMenu *menu = new QMenu(this);
menu->addAction("新建", this, []() { qDebug() << "新建"; });
menu->addAction("打开", this, []() { qDebug() << "打开"; });
menu->addSeparator(); // 分隔线
menu->addAction("退出", this, []() { qDebug() << "退出"; });
menuBtn->setMenu(menu);
// 点击按钮显示菜单
// 也可以设置菜单按钮样式
menuBtn->setStyleSheet(R"(
QPushButton::menu-indicator {
subcontrol-position: right center;
subcontrol-origin: padding;
left: -5px;
}
)");
QLineEdit(单行输入框)
QLineEdit 是用于接收单行文本输入的控件,支持输入验证、密码模式、自动补全等功能。
基本用法
#include <QLineEdit>
// 创建输入框
QLineEdit *lineEdit = new QLineEdit(this);
// 占位文本(输入为空时显示的灰色提示)
lineEdit->setPlaceholderText("请输入用户名");
// 获取和设置文本
lineEdit->setText("默认值");
QString text = lineEdit->text();
// 清空
lineEdit->clear();
// 设置只读
lineEdit->setReadOnly(true); // 只读模式,可选择复制,但不能编辑
lineEdit->setReadOnly(false); // 恢复可编辑
文本变化信号
QLineEdit 提供了多个与文本变化相关的信号,理解它们的区别很重要:
// textChanged: 文本内容任何变化都会触发
// 包括用户输入和程序调用 setText()
connect(lineEdit, &QLineEdit::textChanged, this, [](const QString &text) {
qDebug() << "文本变化(任何原因):" << text;
});
// textEdited: 仅用户编辑时触发
// 调用 setText() 不会触发此信号
connect(lineEdit, &QLineEdit::textEdited, this, [](const QString &text) {
qDebug() << "用户编辑了文本:" << text;
});
// returnPressed: 按下回车键时触发
connect(lineEdit, &QLineEdit::returnPressed, this, [this, lineEdit]() {
QString text = lineEdit->text();
qDebug() << "用户按回车提交:" << text;
// 常用于搜索框、登录表单等
});
// editingFinished: 编辑完成时触发
// 触发条件:按回车 或 输入框失去焦点且内容有变化
connect(lineEdit, &QLineEdit::editingFinished, this, [this, lineEdit]() {
qDebug() << "编辑完成:" << lineEdit->text();
});
// cursorPositionChanged: 光标位置变化
connect(lineEdit, &QLineEdit::cursorPositionChanged, this, [](int oldPos, int newPos) {
qDebug() << "光标从" << oldPos << "移动到" << newPos;
});
信号选择指南:
| 信号 | 触发时机 | 典型用途 |
|---|---|---|
textChanged | 任何文本变化 | 实时验证、搜索建议 |
textEdited | 用户编辑 | 记录用户修改 |
returnPressed | 按回车键 | 提交表单、执行搜索 |
editingFinished | 编辑完成 | 保存数据、验证输入 |
输入验证
限制用户输入内容是表单设计的重要部分:
// 最大长度限制
lineEdit->setMaxLength(20); // 最多 20 个字符
// 整数验证器:只允许输入 0-100 的整数
lineEdit->setValidator(new QIntValidator(0, 100, this));
// 浮点数验证器:允许输入 0.0-100.0,最多 2 位小数
lineEdit->setValidator(new QDoubleValidator(0.0, 100.0, 2, this));
// 正则表达式验证器
// 验证邮箱格式
QRegularExpression emailRegex(R"(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b)");
lineEdit->setValidator(new QRegularExpressionValidator(emailRegex, this));
// 验证手机号(中国大陆)
QRegularExpression phoneRegex(R"(^1[3-9]\d{9}$)");
lineEdit->setValidator(new QRegularExpressionValidator(phoneRegex, this));
// 检查输入是否有效
if (lineEdit->hasAcceptableInput()) {
qDebug() << "输入有效";
} else {
qDebug() << "输入无效";
}
输入掩码
输入掩码提供了更精确的格式控制:
// IP 地址格式
lineEdit->setInputMask("000.000.000.000;_");
// 0 = 必须输入数字
// _ = 空白占位符
// 日期格式
lineEdit->setInputMask("0000-00-00");
// MAC 地址
lineEdit->setInputMask("HH:HH:HH:HH:HH:HH;_");
// H = 必须输入十六进制字符
// 电话号码格式
lineEdit->setInputMask("(999) 999-9999");
// 9 = 可选数字
// 许可证密钥格式(字母转大写)
lineEdit->setInputMask(">AAAAA-AAAAA-AAAAA-AAAAA;#");
// > = 后续字母转大写
// A = 必须输入字母
// # = 空白占位符
输入掩码字符说明:
| 字符 | 含义 |
|---|---|
A | 必须输入字母 |
a | 可选输入字母 |
N | 必须输入字母或数字 |
n | 可选输入字母或数字 |
X | 必须输入任意非空白字符 |
x | 可选输入任意非空白字符 |
9 | 可选输入数字 |
0 | 必须输入数字 |
D | 必须输入 1-9 的数字 |
H | 必须输入十六进制字符 |
> | 后续字母转大写 |
< | 后续字母转小写 |
密码输入
// 密码模式:显示为圆点
lineEdit->setEchoMode(QLineEdit::Password);
// 无回显模式:什么都不显示(高安全场景)
lineEdit->setEchoMode(QLineEdit::NoEcho);
// 编辑时显示,失去焦点后隐藏
lineEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
// 正常模式(默认)
lineEdit->setEchoMode(QLineEdit::Normal);
// 获取显示文本(密码模式下是圆点)
QString displayText = lineEdit->displayText(); // "********"
QString actualText = lineEdit->text(); // "password123"
自动补全
#include <QCompleter>
// 创建补全器
QStringList words;
words << "apple" << "application" << "banana" << "cherry" << "orange";
QCompleter *completer = new QCompleter(words, this);
completer->setCaseSensitivity(Qt::CaseInsensitive); // 不区分大小写
completer->setFilterMode(Qt::MatchContains); // 包含匹配(不是前缀匹配)
lineEdit->setCompleter(completer);
// 文件路径补全
QCompleter *fileCompleter = new QCompleter(this);
fileCompleter->setModel(new QFileSystemModel(fileCompleter));
lineEdit->setCompleter(fileCompleter);
清除按钮
Qt 5.2+ 提供内置清除按钮:
// 显示清除按钮(输入框有内容时显示)
lineEdit->setClearButtonEnabled(true);
// 或者添加自定义操作按钮
QAction *searchAction = lineEdit->addAction(
QIcon(":/icons/search.png"),
QLineEdit::TrailingPosition // 右侧
);
connect(searchAction, &QAction::triggered, this, [this, lineEdit]() {
performSearch(lineEdit->text());
});
// 左侧添加图标
QAction *userAction = lineEdit->addAction(
QIcon(":/icons/user.png"),
QLineEdit::LeadingPosition // 左侧
);
QTextEdit(多行文本编辑)
QTextEdit 用于编辑和显示多行文本,支持纯文本和富文本。
基本用法
#include <QTextEdit>
// 创建文本编辑器
QTextEdit *textEdit = new QTextEdit(this);
// 占位文本
textEdit->setPlaceholderText("请输入内容...");
// 设置纯文本
textEdit->setPlainText("这是一段纯文本");
// 设置富文本(HTML)
textEdit->setHtml("<h1>标题</h1><p>段落内容</p>");
// 获取文本
QString plainText = textEdit->toPlainText(); // 纯文本
QString html = textEdit->toHtml(); // HTML 格式
// 追加文本
textEdit->append("追加的新行");
// 在当前位置插入
textEdit->insertPlainText("插入的文本");
// 清空
textEdit->clear();
只读模式
// 设置只读(用于显示内容)
textEdit->setReadOnly(true);
// 只读模式下用户不能编辑,但可以选择和复制
// 禁用编辑但允许滚动
textEdit->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
文本格式控制
// 设置字体
textEdit->setFont(QFont("Microsoft YaHei", 12));
// 设置当前字符格式
QTextCharFormat format;
format.setFontFamily("Courier New");
format.setFontPointSize(14);
format.setForeground(Qt::blue);
format.setFontWeight(QFont::Bold);
QTextCursor cursor = textEdit->textCursor();
cursor.mergeCharFormat(format); // 应用格式到选中文本
// 设置段落格式
QTextBlockFormat blockFormat;
blockFormat.setAlignment(Qt::AlignCenter);
blockFormat.setIndent(2);
cursor.mergeBlockFormat(blockFormat);
// 限制最大行数
textEdit->setMaximumBlockCount(1000); // 超过后自动删除最旧的行
撤销/重做
// 检查是否可撤销/重做
if (textEdit->document()->isUndoAvailable()) {
textEdit->undo();
}
if (textEdit->document()->isRedoAvailable()) {
textEdit->redo();
}
// 清除撤销历史
textEdit->document()->clearUndoRedoStacks();
QComboBox(下拉框)
QComboBox 提供下拉选择列表,结合了按钮和弹出列表的功能。
基本用法
#include <QComboBox>
// 创建下拉框
QComboBox *comboBox = new QComboBox(this);
// 添加选项
comboBox->addItem("选项1");
comboBox->addItem("选项2");
comboBox->addItem("选项3");
// 批量添加
comboBox->addItems({"选项A", "选项B", "选项C"});
// 带图标的选项
comboBox->addItem(QIcon(":/icons/user.png"), "用户");
comboBox->addItem(QIcon(":/icons/admin.png"), "管理员");
// 设置当前选项
comboBox->setCurrentIndex(0); // 按索引
comboBox->setCurrentText("选项2"); // 按文本
// 获取当前选项
int index = comboBox->currentIndex(); // 索引
QString text = comboBox->currentText(); // 显示文本
QVariant data = comboBox->currentData(); // 关联数据
关联数据
每个选项可以关联额外数据:
// 添加选项时关联数据
comboBox->addItem("北京", 110000); // 显示"北京",存储 110000
comboBox->addItem("上海", 310000);
comboBox->addItem("广州", 440100);
// 获取选中项的数据
int cityCode = comboBox->currentData().toInt();
// 按数据查找
int index = comboBox->findData(310000);
if (index != -1) {
comboBox->setCurrentIndex(index);
}
// 按文本查找
int index = comboBox->findText("北京", Qt::MatchExactly);
信号处理
QComboBox 有两个重载的 currentIndexChanged 信号:
// 索引变化信号
connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [](int index) {
qDebug() << "选中索引:" << index;
});
// 文本变化信号
connect(comboBox, &QComboBox::currentTextChanged, this, [](const QString &text) {
qDebug() << "选中文本:" << text;
});
// 激活信号(用户主动选择时触发)
connect(comboBox, QOverload<int>::of(&QComboBox::activated),
this, [](int index) {
qDebug() << "用户激活了选项:" << index;
});
可编辑下拉框
// 设置可编辑
comboBox->setEditable(true);
// 设置插入策略
comboBox->setInsertPolicy(QComboBox::InsertAtBottom); // 插入到底部
comboBox->setInsertPolicy(QComboBox::InsertAtTop); // 插入到顶部
comboBox->setInsertPolicy(QComboBox::NoInsert); // 不插入
// 自动补全
comboBox->setCompleter(new QCompleter(comboBox->model(), this));
// 限制输入
comboBox->setValidator(new QIntValidator(0, 100, this));
QCheckBox & QRadioButton(复选框和单选框)
复选框
#include <QCheckBox>
// 创建复选框
QCheckBox *checkBox = new QCheckBox("同意用户协议", this);
// 设置选中状态
checkBox->setChecked(true);
// 获取状态
bool isChecked = checkBox->isChecked();
// 监听状态变化
connect(checkBox, &QCheckBox::stateChanged, this, [](int state) {
switch (state) {
case Qt::Unchecked:
qDebug() << "未选中";
break;
case Qt::PartiallyChecked:
qDebug() << "部分选中";
break;
case Qt::Checked:
qDebug() << "已选中";
break;
}
});
// 三态复选框
checkBox->setTristate(true); // 启用三种状态
checkBox->setCheckState(Qt::PartiallyChecked);
单选按钮
单选按钮需要分组使用,同一组内只能选中一个:
#include <QRadioButton>
#include <QButtonGroup>
// 创建按钮组
QButtonGroup *group = new QButtonGroup(this);
// 创建单选按钮
QRadioButton *radio1 = new QRadioButton("男", this);
QRadioButton *radio2 = new QRadioButton("女", this);
QRadioButton *radio3 = new QRadioButton("保密", this);
// 添加到组(带 ID)
group->addButton(radio1, 1);
group->addButton(radio2, 2);
group->addButton(radio3, 3);
// 设置默认选中
radio1->setChecked(true);
// 获取选中项
int selectedId = group->checkedId();
QRadioButton *selectedBtn = qobject_cast<QRadioButton*>(group->checkedButton());
// 监听选中变化
connect(group, QOverload<int>::of(&QButtonGroup::buttonClicked),
this, [](int id) {
qDebug() << "选中了 ID:" << id;
});
// 排他性设置
group->setExclusive(true); // 组内互斥(默认)
group->setExclusive(false); // 允许取消选择
QSlider & QSpinBox(滑块和数字框)
滑块
#include <QSlider>
// 创建滑块
QSlider *slider = new QSlider(Qt::Horizontal, this); // 水平滑块
// QSlider *slider = new QSlider(Qt::Vertical, this); // 垂直滑块
// 设置范围
slider->setRange(0, 100);
slider->setMinimum(0);
slider->setMaximum(100);
// 设置当前值
slider->setValue(50);
// 设置步长
slider->setSingleStep(1); // 键盘方向键步长
slider->setPageStep(10); // PageUp/PageDown 步长
// 刻度设置
slider->setTickPosition(QSlider::TicksBelow); // 刻度位置
slider->setTickInterval(10); // 刻度间隔
// 监听值变化
connect(slider, &QSlider::valueChanged, this, [](int value) {
qDebug() << "滑块值:" << value;
});
// 动作信号(用户拖动时触发)
connect(slider, &QSlider::sliderMoved, this, [](int position) {
qDebug() << "拖动到:" << position;
});
数字框
#include <QSpinBox>
// 创建数字框
QSpinBox *spinBox = new QSpinBox(this);
// 设置范围
spinBox->setRange(0, 100);
// 设置当前值
spinBox->setValue(50);
// 设置步长
spinBox->setSingleStep(5);
// 设置前后缀
spinBox->setPrefix("¥ "); // 前缀
spinBox->setSuffix(" 元"); // 后缀
// 特殊值显示(最小值时显示特殊文本)
spinBox->setSpecialValueText("不限");
// 监听值变化
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged),
this, [](int value) {
qDebug() << "数字框值:" << value;
});
// 浮点数版本
#include <QDoubleSpinBox>
QDoubleSpinBox *doubleSpin = new QDoubleSpinBox(this);
doubleSpin->setRange(0.0, 1.0);
doubleSpin->setSingleStep(0.1);
doubleSpin->setDecimals(2); // 小数位数
滑块与数字框联动
QSlider *slider = new QSlider(Qt::Horizontal, this);
QSpinBox *spinBox = new QSpinBox(this);
slider->setRange(0, 100);
spinBox->setRange(0, 100);
// 双向绑定
connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue);
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged),
slider, &QSlider::setValue);
QProgressBar(进度条)
基本用法
#include <QProgressBar>
// 创建进度条
QProgressBar *progressBar = new QProgressBar(this);
// 设置范围
progressBar->setRange(0, 100);
// 设置当前值
progressBar->setValue(50);
// 设置文本格式
progressBar->setTextVisible(true);
progressBar->setFormat("%p%"); // 显示百分比(默认)
progressBar->setFormat("%v / %m"); // 显示 当前值/最大值
progressBar->setFormat("%p% (%v/%m)"); // 综合格式
// 设置方向
progressBar->setOrientation(Qt::Horizontal); // 水平(默认)
progressBar->setOrientation(Qt::Vertical); // 垂直
// 设置对齐
progressBar->setAlignment(Qt::AlignCenter);
不确定模式
当无法确定进度时,使用不确定模式:
// 进入不确定模式(设置最大值为 0)
progressBar->setRange(0, 0);
// 进度条会显示来回滚动的动画
// 恢复正常模式
progressBar->setRange(0, 100);
progressBar->setValue(50);
实际应用示例
// 模拟文件下载进度
void downloadFile(const QString &url)
{
progressBar->setRange(0, 100);
progressBar->setValue(0);
// 假设这是网络请求的进度回调
connect(networkReply, &QNetworkReply::downloadProgress,
this, [this](qint64 received, qint64 total) {
if (total > 0) {
int percent = static_cast<int>((received * 100) / total);
progressBar->setValue(percent);
}
});
connect(networkReply, &QNetworkReply::finished, this, [this]() {
progressBar->setValue(100);
statusBar()->showMessage("下载完成");
});
}
布局管理
控件需要通过布局管理器组织位置。Qt 提供了多种布局类。
常用布局类型
#include <QVBoxLayout> // 垂直布局
#include <QHBoxLayout> // 水平布局
#include <QGridLayout> // 网格布局
#include <QFormLayout> // 表单布局
// 垂直布局:控件从上到下排列
QVBoxLayout *vLayout = new QVBoxLayout(this);
vLayout->addWidget(new QLabel("标签1"));
vLayout->addWidget(new QLabel("标签2"));
vLayout->addWidget(new QPushButton("按钮"));
// 水平布局:控件从左到右排列
QHBoxLayout *hLayout = new QHBoxLayout();
hLayout->addWidget(new QPushButton("确定"));
hLayout->addWidget(new QPushButton("取消"));
hLayout->addStretch(); // 弹性空间,将控件推到左边
// 网格布局:按行列组织
QGridLayout *grid = new QGridLayout();
grid->addWidget(new QLabel("姓名:"), 0, 0); // 第0行第0列
grid->addWidget(nameEdit, 0, 1); // 第0行第1列
grid->addWidget(new QLabel("年龄:"), 1, 0); // 第1行第0列
grid->addWidget(ageSpin, 1, 1); // 第1行第1列
grid->addWidget(new QLabel("备注:"), 2, 0); // 第2行第0列
grid->addWidget(noteEdit, 2, 1, 1, 2); // 跨2列
// 表单布局:标签-字段成对
QFormLayout *form = new QFormLayout();
form->addRow("用户名:", usernameEdit);
form->addRow("密码:", passwordEdit);
form->addRow("邮箱:", emailEdit);
布局属性
// 边距设置
layout->setContentsMargins(10, 10, 10, 10); // 左、上、右、下
layout->setMargin(10); // 四边相同边距
// 控件间距
layout->setSpacing(10);
// 拉伸因子
hLayout->addWidget(widget1, 1); // 拉伸因子 1
hLayout->addWidget(widget2, 2); // 拉伸因子 2(占更多空间)
// 设置布局到控件
QWidget *widget = new QWidget();
widget->setLayout(layout);
setCentralWidget(widget); // 对于 QMainWindow
嵌套布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 顶部区域
QHBoxLayout *topLayout = new QHBoxLayout();
topLayout->addWidget(new QLabel("搜索:"));
topLayout->addWidget(searchEdit);
topLayout->addWidget(searchBtn);
// 中间区域
QGridLayout *centerLayout = new QGridLayout();
// ...
// 底部区域
QHBoxLayout *bottomLayout = new QHBoxLayout();
bottomLayout->addStretch();
bottomLayout->addWidget(okBtn);
bottomLayout->addWidget(cancelBtn);
// 组合布局
mainLayout->addLayout(topLayout);
mainLayout->addLayout(centerLayout);
mainLayout->addStretch(); // 弹性空间
mainLayout->addLayout(bottomLayout);
完整示例:登录表单
#include <QDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QCheckBox>
#include <QMessageBox>
class LoginDialog : public QDialog
{
Q_OBJECT
public:
LoginDialog(QWidget *parent = nullptr) : QDialog(parent)
{
setWindowTitle("用户登录");
setFixedSize(400, 220);
setupUI();
setupConnections();
}
private:
void setupUI()
{
// 创建控件
QLabel *titleLabel = new QLabel("欢迎登录");
titleLabel->setAlignment(Qt::AlignCenter);
titleLabel->setStyleSheet("font-size: 18px; font-weight: bold; color: #333;");
QLabel *userLabel = new QLabel("用户名:");
QLabel *pwdLabel = new QLabel("密码:");
usernameEdit = new QLineEdit();
usernameEdit->setPlaceholderText("请输入用户名");
usernameEdit->setClearButtonEnabled(true);
passwordEdit = new QLineEdit();
passwordEdit->setPlaceholderText("请输入密码");
passwordEdit->setEchoMode(QLineEdit::Password);
passwordEdit->setClearButtonEnabled(true);
rememberCheck = new QCheckBox("记住密码");
loginBtn = new QPushButton("登录");
loginBtn->setFixedHeight(36);
loginBtn->setStyleSheet(R"(
QPushButton {
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
}
QPushButton:hover {
background-color: #45a049;
}
QPushButton:pressed {
background-color: #3d8b40;
}
)");
cancelBtn = new QPushButton("取消");
cancelBtn->setFixedHeight(36);
// 表单布局
QGridLayout *formLayout = new QGridLayout();
formLayout->addWidget(userLabel, 0, 0);
formLayout->addWidget(usernameEdit, 0, 1);
formLayout->addWidget(pwdLabel, 1, 0);
formLayout->addWidget(passwordEdit, 1, 1);
formLayout->addWidget(rememberCheck, 2, 1);
// 按钮布局
QHBoxLayout *btnLayout = new QHBoxLayout();
btnLayout->addStretch();
btnLayout->addWidget(loginBtn);
btnLayout->addWidget(cancelBtn);
// 主布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(titleLabel);
mainLayout->addSpacing(20);
mainLayout->addLayout(formLayout);
mainLayout->addSpacing(10);
mainLayout->addLayout(btnLayout);
mainLayout->addStretch();
// 设置默认按钮
loginBtn->setDefault(true);
}
void setupConnections()
{
connect(loginBtn, &QPushButton::clicked, this, &LoginDialog::tryLogin);
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
// 回车登录
connect(passwordEdit, &QLineEdit::returnPressed,
loginBtn, &QPushButton::click);
}
private slots:
void tryLogin()
{
QString username = usernameEdit->text().trimmed();
QString password = passwordEdit->text();
// 验证
if (username.isEmpty()) {
QMessageBox::warning(this, "提示", "请输入用户名");
usernameEdit->setFocus();
return;
}
if (password.isEmpty()) {
QMessageBox::warning(this, "提示", "请输入密码");
passwordEdit->setFocus();
return;
}
// 这里应该调用实际的登录逻辑
// 模拟登录成功
if (username == "admin" && password == "123456") {
if (rememberCheck->isChecked()) {
// 保存登录信息
}
accept(); // 关闭对话框,返回 QDialog::Accepted
} else {
QMessageBox::critical(this, "错误", "用户名或密码错误");
passwordEdit->clear();
passwordEdit->setFocus();
}
}
private:
QLineEdit *usernameEdit;
QLineEdit *passwordEdit;
QCheckBox *rememberCheck;
QPushButton *loginBtn;
QPushButton *cancelBtn;
};
下一步
掌握了基础控件后,继续学习 容器控件 了解分组框、标签页、滚动区域等组织控件的容器。