【QT控件】显示类控件

news2025/6/10 11:22:22

目录

一、Label

二、LCD Number

 三、ProgressBar

四、Calendar Widget


QT专栏:QT_uyeonashi的博客-CSDN博客

一、Label

QLabel 可以用来显示文本和图片.

核心属性如下

代码示例: 显示不同格式的文本
1) 在界面上创建三个 QLabel
尺寸放大一些. objectName 分别为 label, label_2, label_3

2) 修改 widget.cpp, 设置三个 label 的属性

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->label->setTextFormat(Qt::PlainText);
    ui->label->setText("这是一段纯文本");
    ui->label_2->setTextFormat(Qt::RichText);
    ui->label_2->setText("<b> 这是一段富文本 </b>");
    ui->label_3->setTextFormat(Qt::MarkdownText);
    ui->label_3->setText("## 这是一段 markdown 文本");
}

3) 运行程序, 观察效果

代码示例: 显示图片
虽然 QPushButton 也可以通过设置图标的方式设置图片, 但是并非是一个好的选择. 更多的时候
还是希望通过 QLabel 来作为一个更单纯的显示图片的方式.
1) 在界面上创建一个 QLabel, objectName 为 label

2) 创建 resource.qrc 文件, 并把图片导入到 qrc 中.

3) 修改 widget.cpp, 给 QLabel 设置图片

// 设置 label 大小和窗口一样大
ui->label->setGeometry(0, 0, 800, 600);
QPixmap pixmap(":/huaji.png");
ui->label->setPixmap(pixmap);

执行程序, 观察效果

这个图片本身的尺寸是 480 * 480, 并没有把 QLabel 填充满.

4) 修改代码, 设置 scaledContents 属性

// 设置内容伸缩
ui->label->setScaledContents(true);

再次运行, 观察效果, 可以看到图片已经被拉伸, 可以把窗口填满了.

5) 此时, 如果拖动窗口大小, 可以看到图片并不会随着窗口大小的改变而同步变化.

为了解决这个问题, 可以在 Widget 中重写 resizeEvent 函数.

// 重写 resizeEvent. 这个函数会在窗口大小发生改变时被自动调用.
void Widget::resizeEvent(QResizeEvent *event) 
{
    // 可以直接通过 this->width() 和 this->height() 设置 label 新的尺寸, 也可以通过event 参数拿到新的尺寸.
    // ui->label->setGeometry(0, 0, this->width(), this->height());
    ui->label->setGeometry(0, 0, event->size().width(), event->size().height());
    
    qDebug() << event->size();
}

执行程序, 此时改变窗口大小, 图片也会随之变化.

于此同时, 在控制台里也能够看到尺寸变化的过程.

⚽ 注意:
此处的 resizeEvent 函数我们没有手动调用, 但是能在窗口大小变化时被自动调用.
这个过程就是依赖 C++ 中的多态来实现的. Qt 框架内部管理着 QWidget 对象表示咱们的窗口. 在窗口大小发生改变时, Qt 就会自动调用 resizeEvent 函数.
但是由于实际上这个表示窗口的并非是 QWidget, 而是 QWidget 的子类, 也就是咱们自己写的 Widget. 此时虽然是通过父类调用函数, 但是实际上执行的是子类的函数(也就是我们重写后的 resizeEvent ).
此处属于是 多态 机制的一种经典用法. 通过上述过程, 就可以把自定义的代码, 插入到框架内部执行. 相当于 "注册回调函数" . 


代码示例: 文本对齐, 自动换行, 缩进, 边距
1) 创建四个 label, objectName 分别是 label 到 label_4并且在 QFrame 中设置 frameShape 为 Box (设置边框之后看起来会更清晰一些)

QFrame 是 QLabel 的父类. 其中 frameShape 属性用来设置边框性质.
• QFrame::Box :矩形边框
• QFrame::Panel :带有可点击区域的面板边框
• QFrame::WinPanel :Windows风格的边框
• QFrame::HLine :水平线边框
• QFrame::VLine :垂直线边框
• QFrame::StyledPanel :带有可点击区域的面板边框,但样式取决于窗口主题

2) 编写 widget.cpp, 给这四个 label 设置属性.

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

    // 设置文字居中对齐
    ui->label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    ui->label->setText("垂直水平居中的文本");

    // 设置自动换行
    ui->label_2->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    ui->label_2->setWordWrap(true);
    ui->label_2->setText("这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本");

    // 设置首行缩进
    ui->label_3->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    ui->label_3->setIndent(20);
    ui->label_3->setText("这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本");

    // 设置边距
    ui->label_4->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    ui->label_4->setMargin(20);
    ui->label_4->setText("这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本");
}

3) 运行程序, 可以看到如下效果
• 第一个 label 垂直水平居中
• 第二个 label 设置了 wordWrap, 能够自动换行
• 第三个 label 设置了 Indent, 左侧和上方和边框有间距. 右侧则没有.
• 第四个 label 设置了 margin, 四个方向均有间距(图上仅体现出三个方向, 下方看不出来).

代码示例: 设置伙伴
1) 创建两个 label 和 两个 radioButton.
objectName 分别问 label , label_2 , radioButton , radioButton_2

📍 此处把 label 中的文本设置为 "快捷键 &A" 这样的形式.
其中 & 后面跟着的字符, 就是快捷键.
可以通过 alt + A 的方式来触发该快捷键.
但是注意, 这里的快捷键和 QPushButton 的不同. 需要搭配 alt 和 单个字母的方式才能触发.

2) 编写 widget.cpp, 设置 buddy 属性
当然这里也可以使用 Qt Designer 直接设置.

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 设置 label 的伙伴 widget
    ui->label->setBuddy(ui->radioButton);
    ui->label_2->setBuddy(ui->radioButton_2);
}

3) 运行程序, 可以看到, 按下快捷键 alt + a 或者 alt + b, 即可选中对应的选项.


二、LCD Number

QLCDNumer 是一个专门用来显示数字的控件. 类似于 "老式计算器" 的效果.

核心属性

代码示例: 倒计时
1) 在界面上创建一个 QLCDNumber , 初始值设为 10.
objectName 为 lcdNumber

2) 修改 widget.h 代码, 创建一个 QTimer 成员, 和一个 updateTime 函数

QTimer* timer;

void updateTime();

3) 修改 widget.cpp, 在构造函数中初始化 QTimer
• QTimer 表示定时器. 通过 start 方法启动定时器之后, 就会每隔一定周期, 触发一次QTimer::timeout 信号.
• 使用 connect 把 QTimer::timeout 信号和 Widget::updateTime 连接起来, 意味着每次触发 QTimer::timeout 都会执行 Widget::updateTime

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

    // 创建 QTimer 实例
    timer = new QTimer(this);
    // 连接信号槽. QTimer 会每隔一定的时间触发一个 timeout 信号. 现在把 timeout 信号和 updateTime 连接起来.
    // 此时意味着每次触发 timeout 信号都会伴随 updateTime 函数的执行.
    connect(timer, &QTimer::timeout, this, &Widget::updateTime);
    // 启动 QTimer, 并且规定每隔 1000ms 触发一次 timeout 信号.
    timer->start(1000);
}

4) 修改 widget.cpp, 实现 updateTime
• 通过 intValue 获取到 QLCDNumber 内部的数值.
• 如果 value 的值归 0 了, 就停止 QTimer . 接下来 QTimer 也就不会触发 timeout 信号了.

void Widget::updateTime() 
{
    qDebug() << "updateTime";
    int value = ui->lcdNumber->intValue();
    if (value <= 0) 
    {
        // 如果时间到, 停止定时器.
        timer->stop();
        return;
    }
    ui->lcdNumber->display(value - 1);
}

5) 执行程序, 可以看到每隔一秒钟, 显示的数字就减少 1.

针对上述代码, 存在两个问题:
1) 上述代码如果直接在 Widget 构造函数中, 通过一个循环 + sleep 的方式是否可以呢?
代码形如

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    int value = ui->lcdNumber->intValue();
    while (true) 
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        if (value <= 0) 
            break;
        ui->lcdNumber->display(value - 1);
    }
}

显然, 这个代码是不行的. 循环会使 Widget 的构造函数无法执行完毕, 此时界面是不能正确构造和显示的.

2) 上述代码如果是在 Widget 构造函数中, 另起一个线程, 在新线程中完成 循环 + sleep 是否可以呢?
代码形如

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    std::thread t([this]() {
        int value = this->ui->lcdNumber->intValue();
        while (true) 
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            if (value <= 0) 
                break;

            this->ui->lcdNumber->display(value - 1);
        }
    });
}

这个代码同样是不行的. Qt 中规定, 任何对于 GUI 上内容的操作, 必须在 主线程 中完成. 像 Widget 构造函数, 以及 connect 连接的 slot 函数, 都是在主线程中调用的. 而我们自己创建的线程则不是.
当我们自己的线程中尝试对界面元素进行修改时, Qt 程序往往会直接崩溃.

✍ 这样的约定主要是因为 GUI 中的状态往往是牵一发动全身的, 修改一个地方, 就需要同步的对其他内容进行调整.
比如调整了某个元素的尺寸, 就可能影响到内部的文字位置, 或者其他元素的位置. 这里一连串的修改, 都是需要按照一定的顺序来完成的.
由于多线程执行的顺序无法保障, 因此 Qt 从根本上禁止了其他线程修改 GUI 状态, 避免后续的一系列问题

 综上所述, 使用定时器, 是实现上述功能的最合理方案.
后续如果我们也有类似的需要 "周期性修改界面状态" 的需求, 也需要优先考虑使用定时器


 三、ProgressBar

使用 QProgressBar 表示一个进度条.

代码示例: 设置进度条按时间增长
1) 在界面上创建进度条, objectName 为 progressBar

其中最小值设为 0, 最大值设为 100. 当前值设为 0.

2) 修改 widget.h, 创建 QTimer 和 updateProgressBar 函数.

QTimer* timer;
void updateProgressBar ();

3) 修改 widget.cpp, 初始化 QTimer
• 此处设置 100ms 触发一次 timeout 信号. 也就是一秒钟触发 10 次.

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Widget::updateProgressBar);
    timer->start(100);
}

4) 修改 widget.cpp, 实现 updateProgressBar

void Widget::updateProgressBar() 
{
    int value = ui->progressBar->value();
    if (value >= 100) 
    {
        timer->stop();
        return;
    }
    ui->progressBar->setValue(value + 1);
}

5) 运行程序, 可以看到进度条中的进度在快速增长.

🏝 在实际开发中, 进度条的取值, 往往是根据当前任务的实际进度来进行设置的.
比如需要读取一个很大的文件, 就可以获取文件的总的大小, 和当前读取完毕的大小, 来设置进度条的比例.
由于上面我们介绍了 Qt 禁止在其他线程修改界面, 因此进度条的更新往往也是需要搭配定时
器来完成的.
通过定时器周期触发信号, 主线程调用对应的 slot 函数. 再在 slot 函数中对当前的任务进度进
行计算, 并更新进度条的界面效果.

代码示例: 创建一个红色的进度条
上述的进度条使用绿色表示的, 但是考虑到有些人可能不喜欢绿色, 因此我们改成一个红色的进条.

不要忘了, QProgressBar 同样也是 QWidget 的子类, 因此我们可以使用 styleSheet 通过样式来修改进度条的颜色.

1) 在界面上创建一个进度条.

2) 在 Qt Designer 右侧的属性编辑器中, 找到 QWidget 的 styleSheet 属性.
编辑如下内容:
• 其中的 chunk 是选中进度条中的每个 "块" . 使用 QProgressBar::text 则可以选中文本.

QProgressBar::chunk {background-1 color: #FF0000;}

同时把 QProcessBar 的 alignment 属性设置为垂直水平居中.

此处如果不设置 alignment , 进度条中的数字会跑到左上角. 这个怀疑是 Qt 本身的 bug, 暂时只能先使用 alignment 来手动调整下.

3) 执行程序, 可以看到如下效果. 我们就得到了一个红色的进度条

通过上述方式, 也可以修改文字的颜色, 字体大小等样式.


四、Calendar Widget

QCalendarWidget 表示一个 "日历" , 形如

核心属性

重要信号

代码示例: 获取选中的日期
1) 在界面上创建一个 QCalendarWidget 和 一个 label
objectName 为 calendarWidget , label

2) 给 QCalendarWidget 添加 slot 函数

void Widget::on_calendarWidget_selectionChanged()
{
    QDate date = ui->calendarWidget->selectedDate();
    qDebug() <<date;
    ui->label->setText(date.toString());
}

3) 执行程序, 可以看到当选择不同的日期时, label 中的内容就会随之改变. 


本篇完!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2406556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

npm安装electron下载太慢,导致报错

npm安装electron下载太慢&#xff0c;导致报错 背景 想学习electron框架做个桌面应用&#xff0c;卡在了安装依赖&#xff08;无语了&#xff09;。。。一开始以为node版本或者npm版本太低问题&#xff0c;调整版本后还是报错。偶尔执行install命令后&#xff0c;可以开始下载…

职坐标物联网全栈开发全流程解析

物联网全栈开发涵盖从物理设备到上层应用的完整技术链路&#xff0c;其核心流程可归纳为四大模块&#xff1a;感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性&#xff0c;例如传感器选型需平衡精度与…

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项

一、条形码识别改名使用教程 打开软件并选择处理模式&#xff1a;打开软件后&#xff0c;根据要处理的文件类型&#xff0c;选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件&#xff0c;就选择 “PDF 识别模式”&#xff1b;若是处理图片文件&…

英国云服务器上安装宝塔面板(BT Panel)

在英国云服务器上安装宝塔面板&#xff08;BT Panel&#xff09; 是完全可行的&#xff0c;尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎&#xff0c;虽然官方主要面向中国大陆…

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…

简约商务通用宣传年终总结12套PPT模版分享

IOS风格企业宣传PPT模版&#xff0c;年终工作总结PPT模版&#xff0c;简约精致扁平化商务通用动画PPT模版&#xff0c;素雅商务PPT模版 简约商务通用宣传年终总结12套PPT模版分享:商务通用年终总结类PPT模版https://pan.quark.cn/s/ece1e252d7df

【Qt】控件 QWidget

控件 QWidget 一. 控件概述二. QWidget 的核心属性可用状态&#xff1a;enabled几何&#xff1a;geometrywindows frame 窗口框架的影响 窗口标题&#xff1a;windowTitle窗口图标&#xff1a;windowIconqrc 机制 窗口不透明度&#xff1a;windowOpacity光标&#xff1a;cursor…

Linux入门课的思维导图

耗时两周&#xff0c;终于把慕课网上的Linux的基础入门课实操、总结完了&#xff01; 第一次以Blog的形式做学习记录&#xff0c;过程很有意思&#xff0c;但也很耗时。 课程时长5h&#xff0c;涉及到很多专有名词&#xff0c;要去逐个查找&#xff0c;以前接触过的概念因为时…

aurora与pcie的数据高速传输

设备&#xff1a;zynq7100&#xff1b; 开发环境&#xff1a;window&#xff1b; vivado版本&#xff1a;2021.1&#xff1b; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程&#xff0c;pc通过pcie传输给fpga&#xff0c;fpga再通过aur…

Springboot 高校报修与互助平台小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;高校报修与互助平台小程序被用户普遍使用&#xff0c;为…

Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用

Linux 内存管理调试分析&#xff1a;ftrace、perf、crash 的系统化使用 Linux 内核内存管理是构成整个内核性能和系统稳定性的基础&#xff0c;但这一子系统结构复杂&#xff0c;常常有设置失败、性能展示不良、OOM 杀进程等问题。要分析这些问题&#xff0c;需要一套工具化、…

MLP实战二:MLP 实现图像数字多分类

任务 实战&#xff08;二&#xff09;&#xff1a;MLP 实现图像多分类 基于 mnist 数据集&#xff0c;建立 mlp 模型&#xff0c;实现 0-9 数字的十分类 task: 1、实现 mnist 数据载入&#xff0c;可视化图形数字&#xff1b; 2、完成数据预处理&#xff1a;图像数据维度转换与…

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器

从本章节开始&#xff0c;进入到函数有多个参数的情况&#xff0c;前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参&#xff0c;ECX是整型的第一个参数的寄存器&#xff0c;那么多个参数的情况下函数如何传参&#xff0c;下面展开介绍参数为整型时候的几种情…

PLC入门【4】基本指令2(SET RST)

04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C)&#xff0c;从 文件 - 主画面&#xff0c;“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…

react更新页面数据,操作页面,双向数据绑定

// 路由不是组件的直接跳转use client&#xff0c;useEffect&#xff0c;useRouter&#xff0c;需3个结合&#xff0c; use client表示客户端 use client; import { Button,Card, Space,Tag,Table,message,Input } from antd; import { useEffect,useState } from react; impor…

Python异步编程:深入理解协程的原理与实践指南

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 持续学习&#xff0c;不断…

Ray框架:分布式AI训练与调参实践

Ray框架&#xff1a;分布式AI训练与调参实践 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 Ray框架&#xff1a;分布式AI训练与调参实践摘要引言框架架构解析1. 核心组件设计2. 关键技术实现2.1 动态资源调度2.2 …

基于小程序老人监护管理系统源码数据库文档

摘 要 近年来&#xff0c;随着我国人口老龄化问题日益严重&#xff0c;独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长&#xff0c;随之而来的是日益突出的老年人问题&#xff0c;尤其是老年人的健康问题&#xff0c;尤其是老年人产生健康问题后&…

理想汽车5月交付40856辆,同比增长16.7%

6月1日&#xff0c;理想汽车官方宣布&#xff0c;5月交付新车40856辆&#xff0c;同比增长16.7%。截至2025年5月31日&#xff0c;理想汽车历史累计交付量为1301531辆。 官方表示&#xff0c;理想L系列智能焕新版在5月正式发布&#xff0c;全系产品力有显著的提升&#xff0c;每…

运行vue项目报错 errors and 0 warnings potentially fixable with the `--fix` option.

报错 找到package.json文件 找到这个修改成 "lint": "eslint --fix --ext .js,.vue src" 为elsint有配置结尾换行符&#xff0c;最后运行&#xff1a;npm run lint --fix