【从零开始的Qt开发指南】(九)Qt 常用控件之显示类控件(下):ProgressBar 与 CalendarWidget 实战进阶


目录

前言

[一、ProgressBar 控件:任务进度的可视化神器](#一、ProgressBar 控件:任务进度的可视化神器)

[1.1 ProgressBar 核心属性解析](#1.1 ProgressBar 核心属性解析)

[1.2 基础用法:快速实现进度条展示](#1.2 基础用法:快速实现进度条展示)

[1.2.1 静态进度展示(固定进度值)](#1.2.1 静态进度展示(固定进度值))

[1.2.2 动态进度展示(结合定时器)](#1.2.2 动态进度展示(结合定时器))

[1.3 样式自定义:打造个性化进度条](#1.3 样式自定义:打造个性化进度条)

[1.4 ProgressBar 常见问题与避坑指南](#1.4 ProgressBar 常见问题与避坑指南)

[问题 1:进度条不更新或更新卡顿](#问题 1:进度条不更新或更新卡顿)

[问题 2:进度文本显示异常(如位置偏移、颜色不对)](#问题 2:进度文本显示异常(如位置偏移、颜色不对))

[问题 3:进度条反向增长不生效](#问题 3:进度条反向增长不生效)

[问题 4:百分比计算错误(如最大值不是 100 时 % p 显示异常)](#问题 4:百分比计算错误(如最大值不是 100 时 % p 显示异常))

[二、CalendarWidget 控件:日期选择的标准化解决方案](#二、CalendarWidget 控件:日期选择的标准化解决方案)

[2.1 CalendarWidget 核心属性解析](#2.1 CalendarWidget 核心属性解析)

[2.2 核心信号解析](#2.2 核心信号解析)

[2.3 基础用法:快速实现日期选择功能](#2.3 基础用法:快速实现日期选择功能)

[2.2 CalendarWidget 常见问题与避坑指南](#2.2 CalendarWidget 常见问题与避坑指南)

[问题 1:无法选择指定日期范围外的日期,但用户仍可通过导航栏切换到该范围](#问题 1:无法选择指定日期范围外的日期,但用户仍可通过导航栏切换到该范围)

[问题 2:自定义样式不生效(如高亮今天、标记特殊日期)](#问题 2:自定义样式不生效(如高亮今天、标记特殊日期))

[问题 3:日期格式化显示异常(如星期显示为英文)](#问题 3:日期格式化显示异常(如星期显示为英文))

总结


前言

在 Qt GUI 开发中,显示类控件不仅要承担信息展示的基础职责,还需满足动态反馈交互选择的核心需求。ProgressBar(进度条)以直观的可视化方式呈现任务进度,是文件上传、数据加载等场景的必备控件;CalendarWidget(日历控件)则为日期选择提供了标准化界面,广泛应用于日程管理、数据筛选等功能中。本文将基于 Qt 5.14 版本,从核心属性、实战案例到进阶技巧,全面拆解这两个控件的使用方法,带你解锁显示类控件的高级玩法!下面就让我们正式开始吧!


一、ProgressBar 控件:任务进度的可视化神器

QProgressBar是 Qt 中用于展示任务进度的核心控件,它通过填充的进度条直观反映任务完成比例,支持自定义进度样式、显示格式和方向,能极大提升用户对长时间任务的感知体验。无论是简单的倒计时进度,还是复杂的文件传输进度展示,ProgressBar 都能轻松胜任。

1.1 ProgressBar 核心属性解析

ProgressBar 的属性围绕进度展示和外观样式展开,以下是最常用的核心属性,结合实用场景帮你快速理解:

属性名 功能说明 取值 / 类型 实用场景
minimum 进度条最小值 int(默认 0) 任务起始点(如文件下载从 0 开始)
maximum 进度条最大值 int(默认 100) 任务终点(如 100% 完成)
value 进度条当前值 int(默认 0) 实时更新任务进度
alignment 进度文本对齐方式 Qt::AlignLeft/AlignCenter/AlignRight 等 优化进度文本显示位置
textVisible 是否显示进度文本 bool(默认 true) 简洁界面可隐藏文本
orientation 进度条方向 Qt::Horizontal(水平,默认)/Qt::Vertical(垂直) 水平适用于顶部 / 底部进度,垂直适用于侧边栏
invertAppearance 是否反向增长 bool(默认 false) 特殊场景下进度从右向左 / 从下向上增长
textDirection 进度文本方向 Qt::LeftToRight/Qt::RightToLeft 适配不同语言排版需求
format 进度文本格式 字符串(支持 % p/% v/% m/% t 占位符) 自定义进度显示(如 "50%""已完成 50/100")

其中,format属性的占位符功能非常实用,四个核心占位符的含义如下:

  • %p:显示百分比(0-100),如 "50%";
  • %v:显示当前进度值,如 "50";
  • %m:显示剩余时间(毫秒级,需结合定时器计算);
  • %t:显示总时间(毫秒级,需结合定时器计算)。

1.2 基础用法:快速实现进度条展示

ProgressBar 的基础用法非常简洁,通过设置minimummaximumvalue三个核心属性,即可实现进度展示。以下是两种常见的基础场景示例:

1.2.1 静态进度展示(固定进度值)

适用于展示已知进度的场景(如操作完成度提示):

cpp 复制代码
#include "widget.h"
#include <QProgressBar>
#include <QLabel>
#include <QVBoxLayout>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("ProgressBar基础用法");
    
    // 创建布局管理器(用于控件排版)
    QVBoxLayout *layout = new QVBoxLayout(this);
    
    // 创建提示标签
    QLabel *tipLabel = new QLabel("任务完成进度:", this);
    layout->addWidget(tipLabel);
    
    // 创建进度条
    QProgressBar *staticProgress = new QProgressBar(this);
    staticProgress->setMinimum(0);       // 最小值0
    staticProgress->setMaximum(100);     // 最大值100
    staticProgress->setValue(68);        // 当前进度68%
    staticProgress->setAlignment(Qt::AlignCenter); // 文本居中
    staticProgress->setFormat("已完成 %p%"); // 显示格式:已完成 68%
    layout->addWidget(staticProgress);
    
    // 添加垂直间距,优化界面
    layout->addSpacing(20);
    
    // 创建垂直进度条(演示方向属性)
    QLabel *verticalTip = new QLabel("垂直进度条演示:", this);
    layout->addWidget(verticalTip);
    
    QProgressBar *verticalProgress = new QProgressBar(this);
    verticalProgress->setOrientation(Qt::Vertical); // 垂直方向
    verticalProgress->setMinimum(0);
    verticalProgress->setMaximum(50);
    verticalProgress->setValue(35);
    verticalProgress->setFormat("%v/%m"); // 显示格式:35/50
    verticalProgress->setFixedHeight(150); // 固定高度,便于展示
    layout->addWidget(verticalProgress, 0, Qt::AlignCenter); // 居中对齐
}

运行程序后,可看到水平进度条显示 "已完成 68%",垂直进度条显示 "35/50",能直观展示不同方向和格式的进度效果。

1.2.2 动态进度展示(结合定时器)

适用于展示实时变化的进度(如文件下载、数据加载),结合 Qt 的 QTimer 控件可实现进度自动增长。

先在.ui文件中拖入ProgressBar控件:

编辑代码:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Widget::handle);

    //启动定时器
    timer->start(100);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handle()
{
    //获取进度条的当前数值
    int value = ui->progressBar->value();
    if(value >= 100)
    {
        //进度条满了,就可以停止定时器了
        timer->stop();
        return;
    }
    ui->progressBar->setValue(value + 1);
}

运行程序后,进度条会从 0% 自动增长到 100%,进度文本实时显示 "XX%",完成后提示 "下100%",完美模拟了进度反馈。

1.3 样式自定义:打造个性化进度条

默认的 ProgressBar 样式较为朴素,通过**Qt Style Sheet(QSS)**可自定义进度条的颜色、边框、圆角等样式,让界面更具设计感。我们可以通过QSS设置进度条的颜色为红色。

首先我们在空间的属性界面找到Style Sheet选项:

点击右侧的"..."进入QSS编辑页面,并输入如下的代码:

点击"OK"后运行程序,可以观察到进度条变为了红色:

当然,我们也可以通过类似的代码设置进度条为其他更加复杂的样式,大家可以在日后使用Qt时自行摸索。

1.4 ProgressBar 常见问题与避坑指南

在使用 ProgressBar 的过程中,容易遇到一些细节问题,这里总结了高频问题及解决方案:

问题 1:进度条不更新或更新卡顿

  • 原因 1:在主线程中执行耗时操作(如大文件读取),阻塞了 UI 线程;
  • 原因 2:定时器周期过短(如 1ms),导致 UI 频繁刷新;
  • 解决方案:
    1. 耗时操作放入子线程,通过信号槽将进度值传递给主线程更新 ProgressBar(注意:Qt 禁止子线程直接操作 UI);
    2. 合理设置定时器周期(建议 50-200ms),平衡刷新频率和性能。

问题 2:进度文本显示异常(如位置偏移、颜色不对)

  • 原因 1:alignment属性设置不当;
  • 原因 2:未通过 QSS 自定义文本样式;
  • 解决方案:
    1. 设置alignmentQt::AlignCenter(默认居中,最稳妥);
    2. 通过 QSS 的QProgressBar::text选择器自定义文本颜色、字体大小。

问题 3:进度条反向增长不生效

  • 原因:invertAppearance属性仅控制进度增长方向,不改变文本方向;
  • 解决方案:若需要文本也反向显示,需同时设置textDirection属性为Qt::RightToLeft

问题 4:百分比计算错误(如最大值不是 100 时 % p 显示异常)

  • 原因:%p占位符会自动根据(value - minimum)/(maximum - minimum)计算百分比,与最大值是否为 100 无关;
  • 示例:若minimum=0maximum=200value=100,则%p显示 50%,无需手动计算。

二、CalendarWidget 控件:日期选择的标准化解决方案

QCalendarWidget 是 Qt 提供的日历控件,支持日期选择、月份 / 年份切换、日期范围限制等功能,无需手动绘制日历界面,可直接集成到项目中,大幅提升开发效率。无论是简单的日期选择框,还是复杂的日程管理界面,CalendarWidget 都能满足需求。

2.1 CalendarWidget 核心属性解析

CalendarWidget 的属性围绕日期展示和交互功能展开,以下是核心属性及实用场景:

属性名 功能说明 取值 / 类型 实用场景
selectedDate 当前选中的日期 QDate 类型 获取用户选择的日期
minimumDate 可选择的最小日期 QDate 类型 限制日期范围(如只能选择今天之后的日期)
maximumDate 可选择的最大日期 QDate 类型 限制日期范围(如只能选择近 30 天的日期)
firstDayOfWeek 每周第一天 Qt::Monday/Qt::Sunday 等 适配不同地区习惯(如国内周一为一周第一天)
gridVisible 是否显示表格边框 bool(默认 true) 简洁界面可隐藏边框
selectionMode 日期选择模式 QAbstractItemView::SingleSelection(默认,单选)等 仅支持单选日期(默认不支持多选)
navigationBarVisible 是否显示导航栏 bool(默认 true) 隐藏导航栏可固定显示某个月份
horizontalHeaderFormat 水平表头格式 QCalendarWidget::ShortDayNames(短名称,如 "一")等 控制星期几的显示格式
verticalHeaderFormat 垂直表头格式 QCalendarWidget::NoVerticalHeader(隐藏)等 控制日期左侧的行号显示
dateEditEnabled 是否允许编辑日期 bool(默认 true) 禁止编辑可防止用户输入非法日期

2.2 核心信号解析

CalendarWidget 的信号主要用于响应日期选择和月份 / 年份切换,以下是最常用的信号:

信号名 触发时机 参数说明 实用场景
selectionChanged() 选中的日期发生改变时 无参数(通过 selectedDate () 获取日期) 实时获取用户选择的日期
activated(const QDate& date) 双击日期或按下回车键时 date:选中的日期 快速确认选择的日期
currentPageChanged(int year, int month) 切换月份 / 年份时 year:新年份;month:新月份 同步更新月份 / 年份显示标签

2.3 基础用法:快速实现日期选择功能

我们先在.ui文件中拖入"Calendar Widget"控件和一个label标签,用于显示选中的日期:

CalendarWidget 的基础用法只需几行代码,即可实现日期选择和展示。以下示例实现了 "选择日期后,在标签中显示选中日期" 的核心功能:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_calendarWidget_selectionChanged()
{
    QDate date = ui->calendarWidget->selectedDate();
    qDebug() << date;

    ui->label->setText(date.toString());
}

运行程序后,选择日历中的任意日期,上方标签会实时显示 ,并且在控制台中也会打印出QDate对象的调试信息,能够直观展示日期选择和格式化功能。

2.2 CalendarWidget 常见问题与避坑指南

问题 1:无法选择指定日期范围外的日期,但用户仍可通过导航栏切换到该范围

  • 原因:minimumDatemaximumDate仅限制日期选择,不限制导航栏切换;
  • 解决方案:重写currentPageChanged信号,当切换到超出范围的月份时,自动切换回最近的合法月份:
cpp 复制代码
connect(calendar, &QCalendarWidget::currentPageChanged, this, [=](int year, int month) {
    QDate currentMonthFirstDay(year, month, 1);
    QDate minDate = calendar->minimumDate();
    QDate maxDate = calendar->maximumDate();
    
    // 如果当前月份小于最小日期的月份,切换到最小日期的月份
    if (currentMonthFirstDay < minDate) {
        calendar->setCurrentPage(minDate.year(), minDate.month());
    }
    // 如果当前月份大于最大日期的月份,切换到最大日期的月份
    else if (currentMonthFirstDay > maxDate) {
        calendar->setCurrentPage(maxDate.year(), maxDate.month());
    }
});

问题 2:自定义样式不生效(如高亮今天、标记特殊日期)

  • 原因 1:QSS 选择器不正确(CalendarWidget 的子控件有固定的对象名,如qt_calendar_today);
  • 原因 2:重写paintCell时未先调用QCalendarWidget::paintCell,覆盖了默认样式;
  • 解决方案:
    1. 参考 Qt 官方文档,使用正确的 QSS 选择器;
    2. 重写paintCell时,先调用父类方法绘制默认样式,再绘制自定义内容。

问题 3:日期格式化显示异常(如星期显示为英文)

  • 原因:QDate::toString的格式符使用不当,默认根据系统 locale 显示;
  • 解决方案:使用中文格式符,或设置 locale 为中文:
cpp 复制代码
// 方式1:使用中文格式符(dddd显示中文星期)
QString dateStr = selected.toString("yyyy年MM月dd日 dddd");

// 方式2:设置locale为中文
calendar->setLocale(QLocale::Chinese);

总结

显示类控件是 Qt 界面开发的重要组成部分,掌握 ProgressBar 和 CalendarWidget 的使用后,可进一步学习 Chart 控件(数据可视化)、OpenGL 控件(3D 图形显示)等高级显示控件,构建更专业、更具交互性的 Qt 应用。

如果本文对你有帮助,欢迎点赞、收藏、转发,如有疑问或建议,欢迎在评论区留言交流~ 后续将推出 Qt 控件系列其他文章,敬请期待!

相关推荐
oioihoii3 小时前
VS Code终端从入门到精通完全指南
开发语言
是一个Bug3 小时前
声明式事务
java·开发语言·面试
武藤一雄3 小时前
C#:深入浅出委托(Delegate/Func/Action/Predicate)
开发语言·后端·microsoft·微软·c#·.net
2501_941982053 小时前
RPA 赋能企业微信外部群:多群同步操作的技术实现
java·开发语言
兵哥工控3 小时前
MFC模拟量转工程量换应用程序实例
c++·mfc·工程量·模拟量
不会代码的小猴3 小时前
C++的第十三天笔记
c++·笔记·算法
OliverH-yishuihan3 小时前
Windows上VScode编译C++
c++·vscode
sugar椰子皮3 小时前
【爬虫框架-5】实现一下之前的思路
开发语言·爬虫·python
沈询-阿里3 小时前
AI Agent系列 - 1 什么是 ReAct Agent?
开发语言·javascript·ecmascript