目录
1.Label控件
属性介绍
三种文本格式的设置应用
编辑
图片与自动拉伸应用
QLable伙伴设置
2.LCD Number控件
属性
Demo:倒计时程序
多线程实现倒计时程序
3.ProgressBar控件
属性
Demo:定时器--进度条随机增长
Qt头文件的前置声明
4.Calendar Widget控件
属性
重要的信号
可以用来显示文本和图片内容,内部含有许多功能,但是在运行后只能用于显示文本和实现编写的功能,不能对文本框进行编辑。
属性 | 说明 |
text | QLabel中的内容 |
textFormat | 文本的格式: Qt::PlainText表示纯文本 Qt::RichText表示富文本(支持html标签) Qt::MarkdownText表示markdown格式 Qt::AutoText表示根据文本内容自动决定文本格式 |
pixmap | QLabel内部包含的图片 |
scaledContents | 设置为true表示内容自动拉伸填充QLabel,fals则相反,通常配合图片拉伸,文本没有什么可拉伸的必要 |
alignment | 对齐方式的设置,可设置为水平和垂直方向如何对齐 Qt::AlignHCenter(水平对齐) Qt::AlignVCenter(垂直对齐) Qt::AlignRight(水平靠右) Qt::AlignLeft(水平靠左) Qt::AlignTop (垂直靠上)Qt::AlignButtom(垂直靠下) |
wordWrap | 是否自动换行 |
indent | 设置文本缩进,水平和竖直方向都生效,设置时传递的参数是像素单位,所以不能传2,表示缩进2个字符。同时该缩进是每一行都会缩进,并非只缩进第一行。 |
margin | 内部文本和边框之间的距离,不同于indent |
openExternalLinks | 是否允许打开一个外部的连接 |
buddy | 给QLabel关联一个伙伴,点击QLabel的时候,就会激活对应的伙伴了 |
对于富文本,会将html标签解析,对于markdown文本格式,会将#解析为标题。
//先让Qlabel铺满整个窗口
QRect window_rect = this->geometry();
ui->label->setGeometry(window_rect);
这样的操作,如果说是在Widget的构造函数中设置的话,那么启动应用程序后,我们改变窗口的大小,不会改变图片的大小,那么如何解决呢?需要重写resizeEvent函数。
在Qt中用户的操作其实有两类,第一类就是信号,第二类而是事件,当用户去改变窗口大小的时候就是一种事件,后续详细的说,那么用户触发拖拽修改窗口大小的时候,就会触发一个resize事件,会自动调用resizeEvent函数。所以重写resizeEvent函数,在内部修改图片的大小,就可以使得图片动态的适应窗口的大小了。
当然用户在改变窗口大小的时候,这个过程并非是一下的,而是在改变的过程中不断的反复调用resizeEvent函数的。
void Widget::resizeEvent(QResizeEvent *event);
// event参数表示触发该函数的时刻,窗口的尺寸数值
// 调用event->size(); 会打印出一个QSize对象
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//先让Qlabel铺满整个窗口
QRect window_rect = this->geometry();
ui->label->setGeometry(window_rect);
//设置图片
QPixmap pixmap(":/people.png");
ui->label->setPixmap(pixmap);
//设置自动拉伸
ui->label->setScaledContents(true);
}
void Widget::resizeEvent(QResizeEvent *event)
{
//获取图片的位置
QRect rect = ui->label->geometry();
//改变图片的大小
ui->label->setGeometry(rect.x(), rect.y(), event->size().width(), event->size().height());
}
在Qt中,QLabel中的纯文本格式下,是可以指定快捷键的,在文本上使用& + 任意一个字符的话,就可以通过alt + 那个字符开触发快捷键了,同时如果该label绑定了一个按钮伙伴,那么触发快捷键,就会触发按钮伙伴了。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置伙伴关系
ui->label->setBuddy(ui->radioButton);
ui->label_2->setBuddy(ui->radioButton_2);
}
该控件时一个专门用来显示数字的控件。
属性 | 说明 |
inValue | 控件显示的数字值(int) |
value | double类型数字 |
digitCount | 显示几位数字 |
mode | 数字的显示形式: QLCDNumber::Dec十进制 QLCDNumber::Hex十六进制 QLCDNumber::Bin二进制 QLCDNumber::Oct八进制 只有十进制的时候,可以显示小数部分 |
segmentStyle | 设置显示风格 QLCDNumber::Flat屏幕的显示风格,数字呈现在一个平面上 QLCDNumber::OutLine轮廓显示风格,数字具有清晰的轮廓和阴影效果 QLCDNumber::Filled填充显示风格,数字被填充颜色并与背景颜色区分开 |
smallDecimalPoint | 设置比较小的小数点 |
Qt中封装了对应的定时器,是使用了信号槽机制实现的。QTimer类创建出来的对象,就会产生一个timeout这样的信号,可以使用start方法来开启定时器,并且参数中设定触发timeout信号的周期。结合connect把这个timeout信号绑定到让LCDNumber数字减少的槽函数即可实现倒计时功能。
void QTimer::start(int msec); //启动定时器并设置定时器的周期
void QTimer::stop(); //停止定时器
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置初始值
ui->lcdNumber->display("10");
//创建一个QTimer对象
timer = new QTimer(this);
//绑定timeout信号的槽函数
connect(timer, &QTimer::timeout, this, &Widget::handlerTimer);
//启动定时器
timer->start(1000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handlerTimer()
{
//先取出LCDNumber中的数字
int int_value = ui->lcdNumber->intValue();
//如果已经为0了--停止定时器
if(int_value <= 0)
{
//停止
timer->stop();
return;
}
ui->lcdNumber->display(int_value - 1);
}
那么可以直接在构造函数之后,使用while循环执行-1的操作吗,显然是不可以的,因为在构造函数中的代码,是在程序未运行之前就需要执行完毕的,所以等到执行完毕之后,程序允许倒计时已经减小为0了。
那么如何实现在循环中休息1秒呢?标准的C++11库中:用于线程休眠的函数。Sleep接口属于Windows平台下的接口,跨平台能力弱。
std::this_thread::sleep_for(std::chrono::seconds(1));
直接使用循环是不可以的,那么如果我们使用多线程+循环呢,对于倒计时的操作创建一个新线程去执行,也是不可以的。在Qt中,里面有一个专门的线程去负责维护更新界面,对于CUI程序来说,内部包含了很多的隐藏的细节,Qt为了保证修改界面的过程中,线程安全不会收到影响,所以Qt禁止了其他线程直接修改界面。
是一个进度条的控件
属性 | 说明 |
minimum | 进度条最小值 |
maximum | 进度条最大值 |
value | 进度条的当前值 |
alignment | 文本在进度条中的对齐方式符合Label的对齐规则 |
textValue | 进度条的数字是否可见 |
orientation | 进度条的方式是水平还是竖直的 |
invertAppearance | 是否是反方向增长 |
textDirection | 文本的朝向 |
format | 显示的数字格式 %p:表示进度的百分比(0-100) %v:表示进度的数值(0-100) %m:表示剩余时间(毫秒) %t:表示总时间(毫秒) |
#include "widget.h"
#include "ui_widget.h"
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置进度条颜色
ui->progressBar->setStyleSheet("QProgressBar::chunk { background-color: red; }");
//设置百分比数字的位置
ui->progressBar->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
//创建定时器对象
timer = new QTimer(this);
//连接信号槽
connect(timer, &QTimer::timeout, this, &Widget::handler);
//启动定时器
timer->start(300);
//设置随机数种子
srand(time(nullptr));
}
Widget::~Widget()
{
delete ui;
}
void Widget::handler()
{
//获取进度条的当前数值
int value = ui->progressBar->value();
if(value >= 100)
{
timer->stop();
return;
}
//获取增加的随机数值
int num = rand() % 5 + 1;
ui->progressBar->setValue(value + num);
}
这里进度条的增长是用定时器出发的随机增长,到了实际的项目中的时候,就可以根据任务的执行情况来进行进度条的增长了。
在上述的代码中我们可以发现我们QTimer的头文件是在cpp文件中包含的,但是我们的QTimer对象却是在.h文件中声明的,这样为什么程序还是可以运行呢?在Qt中有一个专门的头文件,该文件内部包含了所有Qt中的类的前置声明,在我们包含其他任何头文件的时候,都会间接的将这个文件专门的头文件包含,所以就可以使用QTimer的指针或者声明了,不会报错了,但仅仅只能是声明,其他的都不可以使用的,包括创建对象,创建对象会调用构造函数的,也需要调用头文件的函数实现。
那为什么Qt要使用上述的方式呢?主要解决的是编译速度的问题,C/C++的代码编译速度跟其他语言的对比中是很慢的,C/C++的编译速度慢,跟#include有一定的关系,因为各个文件的这种#include错综复杂,在进行各个头文件的展开,那么代码量也就会很大,在平时写#pragma once也是为了该原因,在Qt中使用了前置声明的方式,就使得头文件展开其他头文件的数量减少。但是我们平时也不需要注意这些,与其说减少头文件的包含,不如说提高硬件资源,一般的大公司都是参与专门的“编译集群”,采用分布式编译。而且在C++20标准开始,就引用了模块module带起include了。
表示的是一个日历的控件
属性 | 说明 |
selectDate | 当前选中的日期 |
minimumDate | 最小日期 |
maximumDate | 最大日期 |
gridVisible | 是否显示表格的边框 |
selectionMode | 是否允许选中日期 |
navigationBarVisible | 日历上方标题是否显示 |
horizontalHeaderFormat | 日历上方标题显示日期的格式 |
verticalHeaderFormat | 日历第一列显示的内容格式 |
dateEditEnabled | 是否允许日期被编译 |
firstDayOfWeek | 每周的第一列是周几 |
信号 | 说明 |
selectionChanged(const QDate&) | 当选中的日期发生改变的时候 |
activated(const QDate&) | 当双击一个有效的日期或者按下回车键时发出 |
currentPageChanged(int, int) | 当年份月份改变时发出,形参表示改变后的新年份和月份 |