目录
背景
一、LED设计
1、头文件
2、源文件
二、跑马灯LED位置放置设计
三、实现跑马灯简要代码
1、头文件
2、源文件
3、ui文件
四、效果展示
?参考
背景
????????应项目需求,需要实现一个体现系统运行状态的类似跑马灯效果一样的控件,跑马灯还是本科电子工艺实习期间焊接电路板的时候接触过,初听要用qt实现这个效果,还觉得挺有意思的。开始是调研,理解了一篇博客分享的点阵LED,开始着手实现,最终实现了一个动态的显示状态的小控件。现分享一个实现该控件的一个简要思路。单个LED的设计完全是借鉴过来的,实现跑马灯的效果,主要的工作体现在灯的放置上,也算是存在一个小小的算法设计,虽然这是一个小功能,但是实现之后还是挺有成就感的,特分享出来,供他人做自定义控件的时候借鉴。
一、LED设计
? ? ? ? ?该部分完全借鉴于qt之led(点阵)控件类设计_求知者先的博客-CSDN博客_qt模拟led点阵显示
1、头文件
? ? ? ? ?rgb_led.h
#ifndef __H_RGB_LED_H__
#define __H_RGB_LED_H__
#include <QWidget>
#include <QPainter>
enum LedShape
{
circular,
square,
};
class RGBLed : public QWidget
{
Q_OBJECT
public:
explicit RGBLed(QWidget *parent = nullptr);
void setShape(LedShape shape);
void setShapeToCir(); //设置灯为圆状
void setShapeToSqu(); //设置灯为方状
void setColor(QColor color); //设置led颜色
void setColor(unsigned char red, unsigned char green, unsigned char blue);
QColor getLedColor(); //获取led颜色
//设置led灯大小,此处为绝对大小,即限制了最大最小,直接固定在一个一个大小
void setFixedSize(int width, int hight); //设置led大小
void unFixedSize(int miniWidth = 0,int miniHight = 0); //取消固定大小,一般不建议使用。
//led有两种状态,一种是点亮状态,正常显示设置的颜色,第二种是未点亮(熄灭)的状态,熄灭状态的颜色也可以设置,一般为黑灰色。
bool isLight(); //判断是否点亮
void setLight(bool light = true); //设置是否点亮
void setUnlightColor(QColor color = QColor(50,50,50)); //设置未点亮状态下颜色
//hsv格式转rgb格式,静态模式,外界可直接使用
static void HSVtoRGB(unsigned char& out_r, unsigned char& out_g, unsigned char& out_b, int h, int s, int v);
signals:
private:
void paintEvent(QPaintEvent *paintEvent) override;
void mouseReleaseEvent(QMouseEvent *event) override;
QColor mColor; //led灯颜色
LedShape mShape; //led灯形状
bool lightFlag; //灯是否点亮
QColor unlightColor; //熄灭状态的颜色,默认(50,50,50)
};
#endif // __H_RGB_LED_H__
2、源文件
? ? ? ? ? rgb_led.cpp
#include "rgb_led.h"
RGBLed::RGBLed(QWidget *parent) :
QWidget(parent)
,mShape(square)
,lightFlag(true)
,unlightColor(QColor(50,50,50))
{
setFixedSize(30,30);
mColor = unlightColor;
}
void RGBLed::setShape(LedShape shape)
{
mShape = shape;
}
void RGBLed::setShapeToCir()
{
mShape = circular;
}
void RGBLed::setShapeToSqu()
{
mShape = square;
}
void RGBLed::setFixedSize(int width,int hight)
{
this->setMaximumSize(width,hight);
this->setMinimumSize(width,hight);
update();
}
void RGBLed::unFixedSize(int miniWidth, int miniHight)
{
this->setMaximumSize(10000,10000);
this->setMinimumSize(miniWidth,miniHight);
}
bool RGBLed::isLight()
{
return lightFlag;
}
void RGBLed::setLight(bool light)
{
lightFlag = light;
}
void RGBLed::setUnlightColor(QColor color)
{
unlightColor = color;
}
void RGBLed::setColor(QColor color)
{
mColor = color;
update();
}
void RGBLed::setColor(unsigned char red,unsigned char green,unsigned char blue)
{
mColor = QColor(red,green,blue);
update();
}
QColor RGBLed::getLedColor()
{
return mColor;
}
void RGBLed::paintEvent(QPaintEvent *paintEvent)
{
Q_UNUSED(paintEvent);
QPainter painter(this);
int edgeWidth = 1;
int width = this->width();
int hight = this->height();
painter.setPen(QPen(QColor(255, 255, 255)));
QBrush brush(QColor(255,255,255));
painter.setBrush(brush);
//绘制中心显色区域
if(lightFlag)
painter.setBrush(mColor);
else
painter.setBrush(unlightColor);
if(mShape == square)
painter.drawRect(QRectF(edgeWidth, edgeWidth, width-edgeWidth, hight-edgeWidth));
else if(mShape == circular)
painter.drawEllipse(QRectF(edgeWidth, edgeWidth, width-edgeWidth, hight-edgeWidth));
painter.end();
}
void RGBLed::mouseReleaseEvent(QMouseEvent *event)
{
lightFlag = !lightFlag;
update();
}
void RGBLed::HSVtoRGB(unsigned char& out_r, unsigned char& out_g, unsigned char& out_b, int h, int s, int v)
{
// convert from HSV/HSB to RGB color
// R,G,B from 0-255, H from 0-260, S,V from 0-100
// ref http://colorizer.org/
// The hue (H) of a color refers to which pure color it resembles
// The saturation (S) of a color describes how white the color is
// The value (V) of a color, also called its lightness, describes how dark the color is
int i;
float RGB_min, RGB_max;
RGB_max = v*2.55f;
RGB_min = RGB_max*(100 - s)/ 100.0f;
i = h / 60;
int difs = h % 60; // factorial part of h
float RGB_Adj = (RGB_max - RGB_min)*difs / 60.0f; // RGB adjustment amount by hue
switch (i) {
case 0:
out_r = RGB_max;
out_g = RGB_min + RGB_Adj;
out_b = RGB_min;
break;
case 1:
out_r = RGB_max - RGB_Adj;
out_g = RGB_max;
out_b = RGB_min;
break;
case 2:
out_r = RGB_min;
out_g = RGB_max;
out_b = RGB_min + RGB_Adj;
break;
case 3:
out_r = RGB_min;
out_g = RGB_max - RGB_Adj;
out_b = RGB_max;
break;
case 4:
out_r = RGB_min + RGB_Adj;
out_g = RGB_min;
out_b = RGB_max;
break;
default: // case 5:
out_r = RGB_max;
out_g = RGB_min;
out_b = RGB_max - RGB_Adj;
break;
}
}
二、跑马灯LED位置放置设计
? ? ? ? ? ? 如下图所示,实现一个16*16(rows=16,cols=16)的矩形跑马灯,需要考虑两个问题。
?????????(1)由于灯要交替闪烁,相邻的灯之间需要存在联系,比如此时是奇数灯亮,偶灯等灭;下一个时刻是偶数灯亮,奇数灯灭。所以我们需要把灯按照循环的顺序放入到一个列表中。列表的长度为:total = (rows+cols-2)*2。
? ? ? ? (2)需要确定列表中排在n的灯与它所处位置之间的关系。为了解决这个问题,灯的列表分成s1、s2、s3、s4四段,它们的规律如下:
????????????????s1[0: (cols-2)]段放置位置的横坐标为row=0,纵坐标col从0到(cols-2)依次递增。
? ? ? ? ? ? ? ? s2[(cols-1): (cols+rows-3)]段放置位置的横坐标row从0到(rows-2)依次递增,纵坐标col=cols-1;
????????????????s3[(cols+rows-2): (2*rows-2+cols-2)]段放置位置的横坐标row=?rows -1,纵坐标col从cols-1到1依次递增;?
???????? ???????s4[(2*rows+cols-3) : (2*rows+2*cols - 5)]段放置位置的横坐标row从(rows-1)到1依次递减,纵坐标col=0;
? ? ? ? ? ? ?所以,16*16的跑马灯分成如下4段:
? ? ? ? ? ? ????????? s1:0~14
? ? ? ? ? ????????? ? s2:15~29
? ? ? ? ? ? ? ????????s3:30~44
? ? ? ? ? ? ????????? s4:45~49
? ? ? ? ? ? ?具体对应灯的位置如下图所示。
三、实现跑马灯简要代码
? ? ? ? ? ? 主要包括初始化设置(灯的属性设置和进行放置布局)和使用一个定时器控制灯的亮灭两个部分。
1、头文件
#ifndef __H_DYNAMIC_STATUS_H__
#define __H_DYNAMIC_STATUS_H__
#include <QApplication>
#include <QMainWindow>
#include <QTimer>
#include "rgb_led.h"
#include "statuslabel.h"
namespace Ui {
class DynamicStatus;
}
class DynamicStatus : public QMainWindow
{
Q_OBJECT
public:
explicit DynamicStatus(QWidget *parent = 0);
~DynamicStatus();
void init();
public slots:
void OnLedStatusUpdateTimer();
private:
Ui::DynamicStatus *ui_;
QList<RGBLed*> led_list_;
QTimer led_status_update_timer_;
bool change_status_;
};
2、源文件
#include "dynamic_status.h"
#include "ui_dynamic_status.h"
#include <QGridLayout>
#include <QTimer>
#include <QDebug>
DynamicStatus::DynamicStatus(QWidget *parent) :
QMainWindow(parent),
ui_(new Ui::DynamicStatus),
change_status_(true)
{
ui_->setupUi(this);
init();
}
DynamicStatus::~DynamicStatus()
{
delete ui_;
}
void DynamicStatus::init()
{
int rows = 16; int cols = 16;
int total = (rows + cols - 2) * 2;
int s1_col_start =0;
int s2_row_start =0;
int s3_col_start = cols -1;
int s4_row_start = rows -1;
for(int i = 0; i < total; i++){
RGBLed* led = new RGBLed;
led->setShapeToCir();
led->setFixedSize(30,30);
led->setUnlightColor(QColor(0,0,0));
led_list_.append(led);
if(i < cols -1) {
ui_->gridLayout->addWidget(led,0, s1_col_start++);
} else if (i < (cols + rows -2)) {
ui_->gridLayout->addWidget(led, s2_row_start++, cols - 1);
} else if (i < (2*cols + rows -3)) {
ui_->gridLayout->addWidget(led, rows -1 , s3_col_start--);
} else {
ui_->gridLayout->addWidget(led, s4_row_start--, 0);
}
}
connect(&led_status_update_timer_, &QTimer::timeout, this, &DynamicStatus::OnLedStatusUpdateTimer);
qDebug() << "DynamicStatus::start(): led_list_.size() = " << led_list_.size() ;
led_status_update_timer_.start(1000);
}
void DynamicStatus::OnLedStatusUpdateTimer()
{
static unsigned char offset = 0;
offset = offset+3;
for(int i = 0;i < led_list_.size();i ++)
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char h = i+offset;
RGBLed::HSVtoRGB(r,g,b,h,100,75);
if(change_status_) {
if(i%2 == 0) {
led_list_.at(i)->setColor(0,0,0);
} else {
led_list_.at(i)->setColor(r,255,b);
}
} else {
if(i%2 == 0) {
led_list_.at(i)->setColor(r,255,b);
} else {
led_list_.at(i)->setColor(0,0,0);
}
}
}
change_status_ = ! change_status_;
}
3、ui文件
? ? ? ? 创建一个普通的ui界面,在界面上添加gridLayout控件即可。此处略。
四、效果展示
? ? ? ? ? ? ?录屏,制作成gif,展示,效果如我所想,还不错。
?参考
1、RGBLed class is from CSDN: https://blog.csdn.net/weixin_42887343/article/details/115348953
|