qt显示类控件---QLCDNumber
目录
核心属性
案例演示
案例1:相关属性使用演示
案例2:倒计时(中等难度)
案例3:使用Qmovie帧动画实现倒计时(比较难)
案例4:使用QMetaObject::invokeMethod方法实现不使用信号形式的倒计时(非常难)
QLCDNumer 是⼀个专⻔⽤来显⽰数字的控件.类似于"⽼式计算器"的效果。从本节开始会出现一些比较难,比较超纲的案例,这里会标出,请按需掌握。
核心属性


案例演示
案例1:相关属性使用演示
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//QLCDNumber这个组件是一个专门用来显示数字的控件,类似于计时器那个液晶的显示数字的屏幕//相关属性//intValue QLCDNumber显示的数字值(int),遵循四舍五入的原则//value QLCDNumber显示的数字值(double)//设置value和intValue的⽅法名字为display方法,相当于设置初始数字的方法是display//setDigitCount方法用来显示几位数字//Mode mode()用于提取数字显示形式,一共有4种显示形式,只有十进制的模式才能显示小数点后面的内容//Mode setMode() 设置数字的显示形式qDebug() << ui->lcdNumber->mode();//setSegmentStyle(QLCDNumber::) 设置显示风格,可以设置三种风格//QLCDNumber SegmentStyle() 获得显示风格qDebug() << ui->lcdNumber->segmentStyle();ui->lcdNumber->setSegmentStyle(QLCDNumber::Outline);//setSmallDecimalPoint(bool) 是否设置比较小的小数点ui->lcdNumber->setSmallDecimalPoint(true);//setEnabled(bool) 是否禁用ui->lcdNumber->setDisabled(true); //和上面那个一样的//最常用的就是display方法}Widget::~Widget()
{delete ui;
}
案例2:倒计时(中等难度)
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handle();QTimer* timer;private:Ui::Widget *ui;
};
#endif // WIDGET_H
#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来实现这个不断的信号,当这个定时器类被创建出来并且启动定时器时//会在一个周期时间内不断的触发timeout中断信号//这样结合connect可以吧timeout信号绑定到相应的槽函数中执行逻辑修改LCDBumber中的数字timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &Widget::handle);//start(ms)使用start方法启动定时器,参数是timeout的触发周期,单位毫秒timer->start(1000);
}void Widget::handle()
{int i = ui->lcdNumber->intValue();if (i <= 0){//stop()用于停止定时器timer->stop();return;}ui->lcdNumber->display(--i);
}
Widget::~Widget()
{delete ui;
}

案例3:使用Qmovie帧动画实现倒计时(比较难)
#include "widget.h"
#include "ui_widget.h"
#include<QMovie>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lcdNumber->display(10);//也可以使用QMovie帧动画图片,使用播放时每一帧改变的信号作为改变数字的信号//QMovie 播放的动画(如 GIF)是循环播放的,也就是说这个当前播放的帧的变化是一直存在的,而且变化是均匀的//构造方式是第一个参数是那个.gif动画的路径,第二个参数表示格式提示直接写成QByteArray(),第三个是this,参数一个都不能省略mov = new QMovie(":/emo.gif", QByteArray(), this);//可以使用 setSpeed(int) 就能调“播放倍率”,100 是原始速度,<100 变慢,>100 加快mov->setSpeed(25);connect(mov, &QMovie::frameChanged, this, &Widget::Handler);//播放图片mov->start();//GIF 文件里每一帧可以有自己的 局部延迟(delay),所以变化是不平均的}void Widget::Handler()
{int i = ui->lcdNumber->intValue();if (i <= 0){//让动画不动了此时当前帧不改变mov->stop();return;}ui->lcdNumber->display(--i);
}Widget::~Widget()
{delete ui;
}

案例4:使用QMetaObject::invokeMethod方法实现不使用信号形式的倒计时(非常难)
#include "widget.h"
#include "ui_widget.h"
using namespace std;
#include<unistd.h>
#include<thread>
#include<QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//我们也可以使用sleep/sleep_for函数进行手动的休眠,来制造修改数字的间隔时间ui->lcdNumber->display(10);
// int i = ui->lcdNumber->intValue();
// while (true)
// {
// sleep(1);
// //this_thread::sleep_for(chrono::seconds(1)); 这个比较复杂也是休息一秒
// if (i <= 0)
// {
// break;
// }
// ui->lcdNumber->display(--i);
// }//因为qt是先初始化的Widget再调用show()将效果/控件显示出来,上面初始化时死循环了导致没有调用show从而没有看到效果//也就是我们需要另一个线程帮我们完成数字减少的工作,让主线程构造完显示// std::thread t([this](){ //thread创建线程时一定要指定std::不然不认识这个类型
// int i = this->ui->lcdNumber->intValue();
// while (true)
// {
// sleep(1);
// //this_thread::sleep_for(chrono::seconds(1)); 这个比较复杂也是休息一秒
// if (i <= 0)
// {
// break;
// }
// ui->lcdNumber->display(--i);
// }
// });//t.detach();//可是这样搞还是会报terminate called without an active exception这个错,因为qt为了保证线程安全要求对界面操作必须放在//法三://主线程中完成,对于槽函数来说一般都是由主线程调动的,在槽函数中修改没有线程问题//也就是如果不使用信号与槽这种机制我们只能使用QMetaObject::invokeMethod这个方法将我们的改变逻辑从子线程强制提到主线程中执行//本质还是信号与槽函数,只是不关心信号了,有这个控件就能触发//QMetaObject::invokeMethod(// receiver, // 可以是任意 QObject* (也就是窗口,组件类型的指针)// [](){ /* 你的代码 */ }, // lambda 本体// Qt::QueuedConnection); // 连接类型//一定用 QueuedConnection 把活儿丢回主线程, 丢到主线程取决于第一个参数所依附的线程std::thread t([this](){int i = this->ui->lcdNumber->intValue();while (true){sleep(1);if (i <= 0){break;}i -= 1;QMetaObject::invokeMethod(this, [this, i](){this->ui->lcdNumber->display(i);}, Qt::QueuedConnection);}});t.detach(); //这里不能使用json进行阻塞式等待,因为这里经过事后研究发现show被主线程放到了很后面才执行,尽可能的让其先执行show操作
}Widget::~Widget()
{delete ui;
}
上面这个代码可以形成如下简化:
#include "widget.h"
#include "ui_widget.h"
#include<unistd.h>
#include<thread>
#include<QDebug>
using namespace std;Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lcdNumber->display(10);std::thread t([this](){int i = this->ui->lcdNumber->intValue();while (true){sleep(1);if (i <= 0){break;}i -= 1;QMetaObject::invokeMethod(this, [this, i](){this->ui->lcdNumber->display(i);}, Qt::QueuedConnection);}});t.detach();
}Widget::~Widget()
{delete ui;
}
由于无法在子线程中修改控件的信息,我们使用QMetaObject::invokeMethod意在让处于子线程中的修改逻辑强行压入主线程中执行。
