【Qt】常用控件----显示类控件(QLabel、QLCDNumber、QProgressBar、QCalendarWidget)

目录

前言

书接上文【Qt】常用控件----按钮类控件,今天继续介绍【Qt】常用控件----显示类控件(显示类控件都是继承自QWidget,QWidget涉及的属性、函数、使用方法,在下面介绍的控件中,都是能够使用的)

一、Label

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

核心属性:

属性 说明
text QLabel中的文本
textFormat 文本的格式:Qt::PlainText 纯文本(常用);Qt::RichText 富文本(支持html标签);Qt::MarkdownText markdown格式;Qt::AutoText 根据文本内容自动决定文本格式
pixmap QLabel 内部包含的图片
scaledContents 设为true表示内容自动拉伸填充QLabel,设为false则不会自动拉伸
alignment 对齐方式:可以设置水平和垂直方向如何对齐
wordWrap 设为true内部的文本会自动换行,设为false则内部文本不会自动换行
indent 设置文本缩进,水平和垂直方向都生效
margin 内部文本和边框之间的边距。不同于indent,但是是上下左右四个方向都同时有效。而indent最多只是两个方向有效(具体哪两个方向有效取决于alignment)
openExternalLinks 是否允许打开一个外部的链接(当QLabel文本内容包含url的时候涉及到)
buddy 给QLabel关联⼀个"伙伴",这样点击QLabel时就能激活对应的伙伴。例如伙伴如果是一个QCheckBox,那么该QCheckBox就会被选中

显示不同格式的文本(textFormat)

  • 在界面上创建三个QLabel
  • 设置label的文本格式
cpp 复制代码
    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文本");
  • < b > :表示文本加粗,## :在markdown中解析为二级标题。在纯本文中这两个符号只会倍当成单纯的< b > 和 ##

显示图片(pixmap)

虽然QPushButton也可以通过设置图标的方式设置图片,但是并非是一个好的选择。更多的时候还是希望通过QLabel 来作为一个更单纯的显示图片的方式

  • 在界面上创建一个QLabel,并将QLabel铺满整个窗口
cpp 复制代码
    // 让label铺满整个窗口
    QRect rect = this->geometry();
    ui->label->setGeometry(0, 0, rect.width(), rect.height());
  • 将图片导入(qrc)
  • QLabel设置图片
cpp 复制代码
    QPixmap pixmap(":/Qt.png");
    ui->label->setPixmap(pixmap);
  • 从运行结果可以看到,图片并没有占满整个窗口,原因是图片并不是窗口大小(800*600)尺寸

scaledContents

如果想要图片占满label(窗口),可以使用scaledContents来自动填充

cpp 复制代码
    // 让label铺满整个窗口
    QRect rect = this->geometry();
    ui->label->setGeometry(0, 0, rect.width(), rect.height());

    QPixmap pixmap(":/Qt.png");
    ui->label->setPixmap(pixmap);

    //启动自动拉伸
    ui->label->setScaledContents(true);
  • 此时如果拖动窗口大小,可以看到图片并不会随着窗口大小的改变而同步变化。原因是:label大小设置是在构造函数中,这个设置是一次性的,一旦程序运行起来,QLabel的尺寸就固定下来了。窗口尺寸发生变化,QLabel并不会随着窗口的尺寸变化而变化
  • 为了让QLabel的尺寸随着窗口尺寸的变化而变化,我们这里需要了解事件
  • 用户操作会对应一些信号(点击),Qt中,表示用户操作有两类概念:信号和事件
  • 用户拖拽修改窗口大小会触发resize事件(resizeEvent) ,resize事件是连续变化的
  • 可以让Widget窗口类重写父类(QWidget)的resizeEvent虚函数(在鼠标拖动窗口尺寸过程中,这个函数就会被反复调用执行,每触发一次resizeEvent事件,都会调用一次对应虚函数)
  • 这个过程就是依赖C++中的多态来实现的。Qt框架内部管理着QWidget对象表示咱们的窗口。在窗口大小发生改变时,Qt就会自动调用resizeEvent 函数。但是由于实际上这个表示窗口的并非是QWidget,而是QWidget的子类,也就是自己的Widget。此时虽然是通过父类调用函数,但是实际上执行的是子类的函数(也就是我们重写后的resizeEvent )
  • void Widget::resizeEvent(QResizeEvent *event):这里的event参数非常重要,包含了触发这个resize事件这一时刻的窗口大小尺寸的数值
cpp 复制代码
void Widget::resizeEvent(QResizeEvent *event)
{
    ui->label->setGeometry(0, 0, event->size().width(), event->size().height());
    //qDebug() << event->size();
}

文本对齐、自动换行、缩进、边距

  • 创建四个label并且在QFrame 中设置frameShape 为Box (设置边框之后看起来会更清晰⼀些)
  • 从属性框可以看出继承关系,从上图可以看出,QLabel继承QFrame,QFrame继承自QWidget,所以我们通过QFrame 设置frameShape 为Box
  • 给4个label设置不同属性
  • label设置本文对齐(居中等)
cpp 复制代码
    ui->label->setText("这是一个文本");
    //ui->label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); //垂直水平居中
    //ui->label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); //垂直居中,水平靠右
    ui->label->setAlignment(Qt::AlignRight | Qt::AlignTop); //水平靠右,垂直靠上
  • label_2设置自动换行
cpp 复制代码
ui->label_2->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本。")

可以看到默认情况下,长文本并没有换行,也没有显示完整

cpp 复制代码
	ui->label_2->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本。");
    ui->label_2->setWordWrap(true);
}
  • label_3设置缩进
cpp 复制代码
	ui->label_3->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本。");
    ui->label_3->setWordWrap(true);
    ui->label_3->setIndent(50);

Qt中的缩进是每一行都有缩进

  • label_4设置边距
cpp 复制代码
    ui->label_4->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本。");
    ui->label_4->setWordWrap(true);
    ui->label_4->setMargin(50);

QLabel伙伴设置

  • 创建两个label和两个radioButton

  • 设置伙伴关系

cpp 复制代码
    ui->label->setBuddy(ui->radioButton);
    ui->label_2->setBuddy(ui->radioButton_2);
  • 运行代码,我们发现点击radioButton可以选中选项,但是点击QLabel并不能选中对应的选项,使用alt + a 或者alt + b快捷键可以实现快捷键选中对应选项的操作
  • Qt中,QLabel中写的文本时可以指定快捷键的,此处快捷键的规则功能上要比QPushbutton弱很多。
  • 在文本中使用& 跟上一个字符来表示快捷键(比如& A:表示 alt + a)
  • 绑定了伙伴关系之后,就可以通过快捷键就可以选中对应的单选按钮/复选按钮

二、LCD Number

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

核心属性:

属性 说明
intValue QLCDNumber 显示的数字值(int)
value QLCDNumber 显示的数字值(double)。和intValue是联动的。例如给value设为1.5,intValue的值就是2。设置value和intValue的方法名字为display不是setValue 或者setIntValue
digitCount 显示几位数字
mode 数字显示形式。1. QLCDNumber::Dec :十进制模式,显示常规的十进制数字。2. QLCDNumber::Hex :十六进制模式,以十六进制格式显示数字。3. QLCDNumber::Bin :二进制模式,以二进制格式显示数字。4. QLCDNumber::Oct :八进制模式,以八进制格式显示数字。注意:只有十进制的时候才能显示小数点后的内容
segmentStyle 设置显示风格。1. QLCDNumber::Flat :平面的显示风格,数字呈现在一个平坦的表面上。2. QLCDNumber::Outline :轮廓显示风格,数字具有清晰的轮廓和阴影效果。3. QLCDNumber::Filled :填充显示风格,数字被填充颜色并与背景区分开
smallDecimalPoint 设置比较小的小数点

倒计时

  • 使用QLCDNumber显示一个初始的数值(10),每隔一秒,数字-1,一直到0
  • 对于每隔一秒数字-1的实现,在Qt中封装了对应的定时器(结合了信号槽机制)QTimer类创建出对象,产生一个timeout信号,通过start方法来开启定时器,并且参数中设置触发timeout信号的周期
  • 结合connect,把这个timeout信号绑定到需要的槽函数上,就可以执行逻辑,修改LCDNumber中的数字了
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //设置初始值
    ui->lcdNumber->display("10");
    //创建QTimer示例
    timer = new QTimer(this);
    //把 QTimer的timeout信号和自己的槽函数进行连接
    connect(timer, &QTimer::timeout, this, &Widget::handle);

    //启动定时器,参数是触发timeout的周期,单位是:ms
    timer->start(1000);
}

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

void Widget::handle()
{
   //拿到LCDNumber中的数字
    int value = ui->lcdNumber->intValue();
    if(value <= 0)
    {
        timer->stop();
        return;
    }
    else
    {
        ui->lcdNumber->display(value - 1);
    }
}
  • 通过一个循环+sleep的方式实现
  • 下面代码无法正常显示,循环会使Widget的构造函数无法执行完毕,当构造函数构造完成后,才是w.show()显示窗口,但是此时倒计时已经结束
cpp 复制代码
//main.cpp
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

//widget.cpp
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //设置初始值
    ui->lcdNumber->display("10");
    int value = ui->lcdNumber->intValue();
    while(true)
    {
        //先休眠1s
        std::this_thread::sleep_for(std::chrono::seconds(1));
        if(value <= 0)
            break;
        ui->lcdNumber->display(--value);
    }
}
  • 如果是在Widget构造函数中另起⼀个线程,在新线程中完成循环+sleep是否可以呢?从下面运行结果可以看到是不可以的。Qt中规定,任何对于GUI上内容的操作,必须在主线程中完成
  • Widget构造函数以及connect连接的slot函数都是在主线程中调用的。而我们自己创建的线程则不是
  • 综上所述,使用定时器是实现上述功能的最合理方案
cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //设置初始值
    ui->lcdNumber->display("10");
    int value = ui->lcdNumber->intValue();
    
    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;
            ui->lcdNumber->display(--value);
        }

    });
}

三、ProgressBar

  • 使用QProgressBar表示一个进度条

核心属性:

属性 说明
minimum 进度条最小值
maximum 进度条最大值
value 进度条当前值
alignment 文本在进度条中的对齐方式,Qt::AlignLeft :左对齐;Qt::AlignRight :右对齐;Qt::AlignCenter :居中对齐 ;Qt::AlignJustify :两端对齐
textVisible 进度条的数字是否可见
orientation 进度条的方向是水平还是垂直
invertAppearance 是否是朝反方向增长进度
textDirection 文本的朝向
format 显示的数字格式:%p :表示进度的百分比(0-100);%v :表示进度的数值(0-100);%m :表⽰剩余时间(以毫秒为单位);%t :表示总时间(以毫秒为单位)

设置进度条按时间增长

  • 每隔100ms,进度条+1
  • 将ProgressBar属性的minimum设置为0,maximum设置为100,初始时设置value为0
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()
{
    //获取进度条value
    int value = ui->progressBar->value();
    if(value >= 100)
    {
        timer->stop();
        return;
    }
    ui->progressBar->setValue(value + 1);
}
  • 将上述绿色进度条的颜色改为红色,QProgressBar 同样也是QWidget 的子类,因此我们可以使用styleSheet 通过样式来修改进度条的颜色
cpp 复制代码
QProgressBar::chunk{background-color: #FF0000;}

从下面可以看到,绿色进度条变成了红色了,但是进度条数据24%到左上角了

  • 把QProcessBar 的alignment 属性设置为垂直水平居中

四、Calendar Widget

  • QCalendarWidget 表示一个"日历"

核心属性:

属性 说明
selectDate 当前选中的日期
minimumDate 最小日期
maximumDate 最大日期
firstDayOfWeek 每周的第一天(也就是日历的第一列)是周几
gridVisible 是否显示表格的边框
selectionMode 是否允许选择日期
navigationBarVisible 日历上方标题是否显示
horizontalHeaderFormat 日历上方标题显示的日期格式
verticalHeaderFormat 日历第一列显示的内容格式
dateEditEnabled 是否允许日期被编辑

重要信号:

信号 说明
selectionChanged(const QDate&) 当选中的日期发生改变时发出
activated(const QDate&) 当双击一个有效的日期或者按下回车键时发出,形参是一个QDate类型,保存了选中的日期
currentPageChanged(int, int) 当年份月份改变时发出,形参表示改变后的新年份和月份

获取选中的日期

  • 在界面上创建一个QCalendarWidget 和一个label

  • 给QCalendarWidget 添加slot函数

  • QDate数据不能直接传入到setText中,因为setText需要传入QString类型的数据,所以使用toString将QDate数据转换成QString类型数据即可

cpp 复制代码
void Widget::on_calendarWidget_selectionChanged()
{
    QDate date = ui->calendarWidget->selectedDate();
    qDebug() << date;
    ui->label->setText(date.toString());
}
相关推荐
她和夏天一样热27 分钟前
【观后感】Java线程池实现原理及其在美团业务中的实践
java·开发语言·jvm
C_心欲无痕28 分钟前
浏览器缓存: IndexDB
前端·数据库·缓存·oracle
lkbhua莱克瓦2429 分钟前
进阶-索引3-性能分析
开发语言·数据库·笔记·mysql·索引·性能分析
郑州光合科技余经理34 分钟前
技术架构:上门服务APP海外版源码部署
java·大数据·开发语言·前端·架构·uni-app·php
剑来.1 小时前
事务没提交,数据库为什么会越来越慢?
数据库·oracle
篱笆院的狗1 小时前
Java 中的 DelayQueue 和 ScheduledThreadPool 有什么区别?
java·开发语言
2501_941809141 小时前
面向多活架构与数据地域隔离的互联网系统设计思考与多语言工程实现实践分享记录
java·开发语言·python
qualifying1 小时前
JavaEE——多线程(4)
java·开发语言·java-ee
韦东东2 小时前
DeepSeek:R1本地RAG 问答: 功能新增,附 六大关键技术优化路径参考
数据库·mysql
Leon-Ning Liu2 小时前
19c RAC 环境 Patch 38326922 应用实战
数据库·oracle