Qt常用控件——QLCDNumber
文章目录
- QLCDNumber核心属性
- 倒计时小程序
- 倒计时小程序相关问题
QLCDNumber核心属性
QLCDNumber
是专门用来显示数字的控件,类似于这样:
属性 | 说明 |
---|---|
intValue | 获取的数字值(int). |
value | 获取的数字值(double) 和intValue是联动的 例如value设为1.5,intValue值就是2 设置value和intValue的方法名为 display |
digitCount | 显示几位数字 |
mode | 数字显示形式:QLCDNumber::Dec :显示十进制(只有十进制才能显示小数点后的内容)QLCDNumber::Hex :显示十六进制QLCDNumber::Bin :显示二进制QLCDNumber::Oct :显示八进制 |
segmentStyle | 设置显示风格:QLCDNumber::Flat :平面显示风格,数字呈现在平坦的表面QLCDNumber::Outline :轮廓风格显示,数字有清晰的轮廓和阴影效果QLCDNumber::Filled :填充显示风格,数字被填充颜色与背景区分 |
smallDecimalPoint | 设置较小的小数点 |
倒计时小程序
使用QLCDNumber
显示一个初始值,每隔一秒数字减一,一直到0
不同显示风格:
设置起始10秒:
ui->lcdNumber->display("10");
接下来的关键就是“每秒钟-1”这个效果。
这个属于——周期性执行某个逻辑,这类组件叫做“定时器”。
在C++标准库并没有提供定时器实现,Boost里面实现了。
另外Qt里面也封装了对应的计算器,而且封装了信号槽机制:
QTimer
类:通过这个类创建出的对象,就会产生一个
timeout
这样的信号,可以通过start
方法来开启定时器,并且设定参数触发timeout
信号的周期。然后这样就可以结合
connect
把这个timeout
信号绑定到需要的槽函数当中,就可以修改执行逻辑,修改LCDNumber中的数字了
widget.h
:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handle();
private:
Ui::Widget *ui;
QTimer *timer;
};
#endif // WIDGET_H
widget.cpp
:
#include "widget.h"
#include "ui_widget.h"
#include<QTimer>
#include<QDebug>
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);
//启动计时器 参数为触发周期 单位是 ms
timer->start(1000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
//获取lcdNumber数字
int val = ui->lcdNumber->intValue();
if(val <= 0)
{
timer->stop();
return;
}
ui->lcdNumber->display(val - 1);
}
倒计时小程序相关问题
上面是借助QTimer
完成的倒计时功能,也可以使用while循环,每一秒减一来实现
Tips:
Windows
提供了Sleep
的接口,只能在Visual Studio里面使用;而目前Qt采用的是mingw,windows版本的gcc,是无法使用
Sleep
的;C++11标准库引入了
sleep
操作:sleep_for
#include "widget.h"
#include "ui_widget.h"
#include<thread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
int val = ui->lcdNumber->intValue();
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if(val <= 0)
{
break;
}
ui->lcdNumber->display(--val);
}
}
Widget::~Widget()
{
delete ui;
}
运行程序之后发现,并没有显示窗口,而是运行完毕之后,才显示计算完毕的窗口:
这是因为这段逻辑,都是在构造函数当中完成的,构造完毕之后,才会显示
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
如果构造函数当中创建一个线程,然线程去执行这段逻辑,是否可以?
#include "widget.h"
#include "ui_widget.h"
#include<thread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// int val = ui->lcdNumber->intValue();
// while(true)
// {
// std::this_thread::sleep_for(std::chrono::seconds(1));
// if(val <= 0)
// {
// break;
// }
// ui->lcdNumber->display(--val);
// }
std::thread t([this](){
int val = this->ui->lcdNumber->intValue();
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if(val <= 0)
{
break;
}
ui->lcdNumber->display(--val);
}
});
}
Widget::~Widget()
{
delete ui;
}
运行程序之后,报错了:
这是因为Qt里面,界面有一个专门的线程去负责维护更新的(主线程,main函数所在线程)
对于GUI来说,内部包含了很多隐藏状态,Qt为了保证修改界面的工程中,线程安全不会受到影响,Qt禁止了其他线程直接修改界面。
上面的操作就是修改界面的操作。
因此Qt为了保证线程的按照,直接要求所有对界面的修改操作,必须在主线程当中完成。
对于Qt的槽函数来说,默认情况下,槽函数都是由主线程调用的,在槽函数当中修改界面没有任何问题。
主线程当中,有一个事件循环,在main函数当中:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec(); //事件循环
}
a.exec
会使主线程进入事件循环,每执行一次循环,就会有固定的事情要做
综上所述,使用定时器实现倒计时,是较为合理的方案,后续如果有周期性修改界面状态的操作,优先考虑定时器