QT 实现跑马灯

目录

背景

一、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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值