当前位置: 首页 > article >正文

LVGL仪表盘逆时针

背景

LVGL 8.3 自带的lv_meter控件,目前只支持顺时针显示,但是,项目上刚好用到了逆时针。官网论坛有讨论通过arc + lv_meter 组合的方式实现。这个方法在模拟器上可以,但是放到板子上,刻度显示不出来,只显示一个完整的弧,这不是我要的效果,具体为何如此,深入研究了一番,没找到原因。唯一的差别在模拟器使用的SDL,板子使用的FB。

思路

鉴于arc + lv_meter 组合的方案没有通过,转而换个思路。由于arc是支持逆时针的,那就先研究arc的实现方式,然后在lv_meter代码中修改。按照这个思路,又研究了一番源码,找到了方法。

实现

lv_meter_indicator_t
typedef struct
    {
        lv_meter_scale_t *scale;
        lv_meter_indicator_type_t type;
        lv_opa_t opa;
        int32_t start_value;
        int32_t end_value;
        union
        {
            // ... ...
            struct
            {
                uint16_t width;
                const void *src;
                lv_color_t color;
                int16_t r_mod;
                uint16_t mode; // 0: clockwise; 1: counter clockwise
            } arc;
            // ... ...
        } type_data;
    } lv_meter_indicator_t;

增加mode字段,用于描述顺时针还是逆时针。

lv_meter_add_arc
lv_meter_indicator_t *lv_meter_add_arc(lv_obj_t *obj, lv_meter_scale_t *scale, uint16_t width, lv_color_t color,
                                       int16_t r_mod, uint16_t mode)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_meter_t *meter = (lv_meter_t *)obj;
    lv_meter_indicator_t *indic = _lv_ll_ins_head(&meter->indicator_ll);
    LV_ASSERT_MALLOC(indic);
    lv_memset_00(indic, sizeof(lv_meter_indicator_t));
    indic->scale = scale;
    indic->opa = LV_OPA_COVER;

    indic->type = LV_METER_INDICATOR_TYPE_ARC;
    indic->type_data.arc.width = width;
    indic->type_data.arc.color = color;
    indic->type_data.arc.r_mod = r_mod;
    indic->type_data.arc.mode = mode;

    lv_obj_invalidate(obj);
    return indic;
}

增加输入参数,用于配置mode。

draw_arcs
static void draw_arcs(lv_obj_t *obj, lv_draw_ctx_t *draw_ctx, const lv_area_t *scale_area)
{
    // ... ...
     _LV_LL_READ_BACK(&meter->indicator_ll, indic)
    {
        lv_meter_scale_t *scale = indic->scale;
        int32_t start = scale->rotation;
        int32_t end = scale->rotation + scale->angle_range;
        int32_t start_angle;
        int32_t end_angle;

        if (indic->type_data.arc.mode == 0)
        {
            start_angle = lv_map(indic->start_value, scale->min, scale->max, start, end);
            end_angle = lv_map(indic->end_value, scale->min, scale->max, start, end);
        }
        else
        {
            start_angle = lv_map(indic->start_value, scale->min, scale->max, end, start);
            end_angle = lv_map(indic->end_value, scale->min, scale->max, end, start);
        }

        arc_dsc.start_angle = start_angle;
        arc_dsc.end_angle = end_angle;
        part_draw_dsc.radius = r_out + indic->type_data.arc.r_mod;
        part_draw_dsc.sub_part_ptr = indic;
        part_draw_dsc.p1 = &scale_center;

        lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
        if (indic->type_data.arc.mode == 0)
        {
            lv_draw_arc(draw_ctx, &arc_dsc, &scale_center, part_draw_dsc.radius, start_angle, end_angle);
        }
        else
        {
            lv_draw_arc(draw_ctx, &arc_dsc, &scale_center, part_draw_dsc.radius, end_angle, start_angle);
        }
        lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
    }
    // ... ...
}

根据mode值,进行不同设置。

inv_arc
static void inv_arc(lv_obj_t *obj, lv_meter_indicator_t *indic, int32_t old_value, int32_t new_value)
{
    bool rounded = lv_obj_get_style_arc_rounded(obj, LV_PART_ITEMS);

    lv_area_t scale_area;
    lv_obj_get_content_coords(obj, &scale_area);

    lv_coord_t r_out = lv_area_get_width(&scale_area) / 2;
    lv_point_t scale_center;
    scale_center.x = scale_area.x1 + r_out;
    scale_center.y = scale_area.y1 + r_out;

    r_out += indic->type_data.arc.r_mod;

    lv_meter_scale_t *scale = indic->scale;
    int32_t start = scale->rotation;
    int32_t end = scale->rotation + scale->angle_range;
    int32_t start_angle;
    int32_t end_angle;

    if (indic->type_data.arc.mode == 0)
    {
        start_angle = lv_map(old_value, scale->min, scale->max, start, end);
        end_angle = lv_map(new_value, scale->min, scale->max, start, end);
    }
    else
    {
        start_angle = lv_map(old_value, scale->min, scale->max, end, start);
        end_angle = lv_map(new_value, scale->min, scale->max, end, start);
    }

    lv_area_t a;
    lv_draw_arc_get_area(scale_center.x, scale_center.y, r_out, LV_MIN(start_angle, end_angle), LV_MAX(start_angle, end_angle), indic->type_data.arc.width, rounded, &a);
    lv_obj_invalidate_area(obj, &a);
}

根据mode值,进行不同设置。


http://www.kler.cn/news/341056.html

相关文章:

  • IDEA之手动添加作者信息
  • 『网络游戏』服务器使用PESorket【13】
  • 使用HttpsClient来idea发送请求
  • Android targetSdkVersion 升级为34 问题处理
  • 减少重复的请求之promise缓存池(闭包版) —— 缓存promise,多次promise等待并返回第一个promise的结果
  • 75.【C语言】文件操作(2)
  • 计算机毕业设计—基于python技术的机器学习、深度学习毕业设计选题的一些思考及参考
  • Pikachu-File Inclusion-远程文件包含
  • redis——哨兵机制
  • Vortex GPGPU的github流程跑通与功能模块波形探索(二)
  • 环形缓冲区(Ring Buffer)在STM32 HAL库中的应用:防止按键丢失
  • 第69期 | GPTSecurity周报
  • 三色标记算法
  • prctl的函数和pthread_self函数
  • Linux中的多线程
  • 打造直播美颜平台的关键技术:视频美颜SDK的深度解析
  • QDesktopWidget Class
  • Chromium 中js Fetch API接口c++代码实现(一)
  • HarmonyOS第一课 05 从简单的页面开始-开发01
  • Dockerfile搭建环境案例