Scale (标尺)(lv_scale)

Overview(概述)

显示原文

Scale Widgets show linear or circular scales with configurable ranges, tick counts, placement, labeling, and sub-sections (scale_sections) with custom styling.


量表部件(Scale Widgets)可显示线性或圆形量表,其具有可配置的范围、刻度数量、刻度位置、刻度标签以及带有自定义样式的子部分(scale_sections)。

Parts and Styles(部分和样式)

显示原文

The scale widget is divided in the following three parts:

  • LV_PART_MAIN Main line. See blue line in the example image.

  • LV_PART_ITEMS Minor ticks. See red minor ticks in the example image.

  • LV_PART_INDICATOR Major ticks and its labels (if enabled). See pink labels and green major ticks in the example image.


标尺控件分为以下三个部分:

  • LV_PART_MAIN 主线。请参阅后面示例演示中的蓝线。

  • LV_PART_ITEMS 每个主刻度之间的次刻度。请参阅后面示例演示中的红色次刻度。

  • LV_PART_INDICATOR 主要刻度及其标签(如果启用)。 请参阅后面示例演示查看粉红色标签和绿色主刻度。

../../_images/scale.png

Usage(用法)

Mode

显示原文

When a Scale Widget is created, it starts out in MODE LV_SCALE_MODE_HORIZONTAL_BOTTOM. This makes the scale horizontal with tick marks below the line. If you need it to have a different shape, orientation or tick position, use lv_scale_set_mode(scale, mode), where mode can be any of these values:


当创建一个量表部件(Scale Widget)时,它最初处于 LV_SCALE_MODE_HORIZONTAL_BOTTOM`模式下。这会使量表呈水平方向,且刻度标记位于线条下方。如果需要它具有不同的形状、方向或刻度位置,可使用 :cpp:expr:`lv_scale_set_mode(scale, mode),其中 mode 可以是以下任意值:

Setting ranges(设置范围)

显示原文

A Scale starts its life with a default range of [0..100]. You can change this range with lv_scale_set_range(scale, min, max).


量表在初始创建时默认的范围是 [0..100]。你可以使用 :cpp:expr:`lv_scale_set_range(scale, min, max)`来更改这个范围。

Tick drawing order(刻度绘制顺序)

显示原文

Normally ticks and their labels are drawn first and the main line is drawn next, giving the ticks and their labels the appearance of being underneath the main line when there is overlap. You can reverse this sequence if you wish, making the ticks and labels appear on top the main line, using lv_scale_set_draw_ticks_on_top(scale, true). (This effect can be reversed by passing false instead.)

Example with with ticks and labels drawn under the main line (default):

../../_images/scale_ticks_below.png

Example with ticks and labels drawn on top of the main line:

../../_images/scale_ticks_on_top.png

通常情况下,刻度及其标签会先被绘制出来,然后再绘制主线,这样当存在重叠情况时,刻度及其标签看起来就像是在主线的下方。如果需要的话,你可以反转这个绘制顺序,使用 lv_scale_set_draw_ticks_on_top(scale, true)`让刻度和标签显示在主线的上方(若传递 ``false` 则可恢复原来的效果)。

刻度和标签绘制在主线下方(默认情况)的示例:

../../_images/scale_ticks_below.png

刻度和标签绘制在主线上方的示例:

../../_images/scale_ticks_on_top.png

Configure ticks(配置刻度)

显示原文

You configure the major and minor ticks of a Scale by calling 2 functions:

If you want labels to be drawn with the major ticks, call lv_scale_set_label_show(scale, true). (Pass false to hide them again.)

By default, the labels shown are the numeric values of the scale at the major tick points. Can you specify different label content by calling lv_scale_set_text_src(scale, custom_labels) where custom_labels is an array of string pointers. Example:

static char * custom_labels[3] = {"One", "Two", NULL};

Note that a NULL pointer is used to terminate the list.

The content of the buffers pointed to need to remain valid for the life of the Scale.

For a Scale in one of the ..._ROUND_... modes, you can optionally get it to rotate the major-tick labels to match the rotation of the major ticks using lv_obj_set_style_transform_rotation(scale, LV_SCALE_LABEL_ROTATE_MATCH_TICKS, LV_PART_INDICATOR).

Alternately, labels can be rotated by a fixed amount (for any Scale mode). This example rotates labels by 20 degrees: lv_obj_set_style_transform_rotation(scale, 200, LV_PART_INDICATOR).

Or both of the above can be done at the same time: lv_obj_set_style_transform_rotation(scale, LV_SCALE_LABEL_ROTATE_MATCH_TICKS + 200, LV_PART_INDICATOR).

Some labels of the Scale might be drawn upside down (to match the tick) if the Scale includes a certain angle range. If you don't want this, to automatically rotate the labels to keep them upright, an additional flag can be used. Labels that would be upside down are then rotated 180 lv_obj_set_style_transform_rotation(scale, LV_SCALE_LABEL_ROTATE_MATCH_TICKS | LV_SCALE_LABEL_ROTATE_KEEP_UPRIGHT, LV_PART_INDICATOR). Labels can also be moved a fixed distance in X and Y pixels using lv_obj_set_style_translate_x(scale, 10, LV_PART_INDICATOR).

备注

The major tick value is calculated with the lv_map API (when not setting custom labels), this calculation takes into consideration the total number of ticks and the Scale range, so the label drawn can present rounding errors when the calculated value is a floating-point value.

The length of the ticks can be configured with the length Style property on the LV_PART_INDICATOR for major ticks and LV_PART_ITEMS for minor ticks. Example with local Style: lv_obj_set_style_length(scale, 5, LV_PART_INDICATOR) for major ticks and lv_obj_set_style_length(scale, 5, LV_PART_ITEMS) for minor ticks. The ticks can be padded in either direction (outwards or inwards) for ..._ROUND_... Scales only with: lv_obj_set_style_radial_offset(scale, 5, LV_PART_INDICATOR) for major ticks and lv_obj_set_style_radial_offset(scale, 5, LV_PART_ITEMS) for minor. Using length and radial offset together allows total control of the tick position.

It is also possible to offset the labels from the major ticks (either positive or negative) using lv_obj_set_style_pad_radial(scale, 5, LV_PART_INDICATOR)


你可以通过调用以下两个函数来配置量表(Scale)的主刻度和次刻度:

如果你希望在主刻度处绘制标签,可调用 lv_scale_set_label_show(scale, true)`(传递 ``false` 可再次隐藏它们)。

默认情况下,显示的标签是量表在主刻度点处的数值。你可以通过调用 lv_scale_set_text_src(scale, custom_labels)`来指定不同的标签内容,其中 ``custom_labels` 是一个字符串指针数组。示例如下:

static char * custom_labels[3] = {"One", "Two", NULL};

请注意,使用 NULL 指针来终止列表。指向缓冲区的内容在量表的整个生命周期内都需要保持有效。

所指向的缓冲区的内容在量表的整个生命周期内都需要保持有效。

对于处于 ..._ROUND_... 模式之一的量表,你可以选择让它旋转主刻度标签以使其与主刻度的旋转相匹配,使用 lv_obj_set_style_transform_rotation(scale, LV_SCALE_LABEL_ROTATE_MATCH_TICKS, LV_PART_INDICATOR)

或者,标签也可以按固定角度旋转(适用于任何量表模式)。以下示例将标签旋转 20 度:cpp:expr:lv_obj_set_style_transform_rotation(scale, 200, LV_PART_INDICATOR)

又或者上述两种操作可以同时进行:cpp:expr:lv_obj_set_style_transform_rotation(scale, LV_SCALE_LABEL_ROTATE_MATCH_TICKS + 200, LV_PART_INDICATOR)

如果量表涵盖了特定的角度范围,部分量表的标签可能会上下颠倒绘制(为了与刻度匹配)。如果你不希望这样,想要自动旋转标签使其保持正向,可以使用一个额外的标志。原本会上下颠倒的标签将会旋转 180 度:lv_obj_set_style_transform_rotation(scale, LV_SCALE_LABEL_ROTATE_MATCH_TICKS | LV_SCALE_LABEL_ROTATE_KEEP_UPRIGHT, LV_PART_INDICATOR)。 也可以使用 :cpp:expr:`lv_obj_set_style_translate_x(scale, 10, LV_PART_INDICATOR)`将标签在 X 和 Y 像素方向上移动固定的距离。

备注

主刻度的值在未设置自定义标签时是通过 :cpp:expr:`lv_map`来计算的,该计算会考虑刻度总数和量表范围,所以当计算出的值是浮点值时,绘制的标签可能会出现舍入误差。

刻度的长度可以通过在 LV_PART_INDICATOR`上针对主刻度以及在 :cpp:enumerator:`LV_PART_ITEMS`上针对次刻度使用长度样式属性来配置。使用本地样式的示例如下:针对主刻度使用 :cpp:expr:`lv_obj_set_style_length(scale, 5, LV_PART_INDICATOR) ,针对次刻度使用 lv_obj_set_style_length(scale, 5, LV_PART_ITEMS)。仅对于 ..._ROUND_... 模式的量表,刻度可以在任意方向(向外或向内)进行填充,针对主刻度使用 lv_obj_set_style_radial_offset(scale, 5, LV_PART_INDICATOR),针对次刻度使用 lv_obj_set_style_radial_offset(scale, 5, LV_PART_ITEMS)。将长度和径向偏移一起使用可以完全控制刻度的位置。

还可以使用:cpp:expr:`lv_obj_set_style_pad_radial(scale, 5, LV_PART_INDICATOR)`将标签相对于主刻度进行正向或负向的偏移。

Sections(剖面)

显示原文

Sections make it possible for portions of a Scale to convey meaning by using different Style properties to draw them (colors, line thicknesses, font, etc.).

A Section represents a sub-range of the Scale, whose Styles (like Cascading Style Sheets) take precedence while drawing the PARTS (lines, arcs, ticks and labels) of the Scale that are within the range of that Section.

If a PART of a Scale is within the range of 2 or more Sections (i.e. those Sections overlap), the Style's properties belonging to the most recently added Section takes precedence over the same style properties of other Section(s) that "involve" that PART.


通过使用不同的样式属性(颜色、线条粗细、字体等)来绘制,区段(Sections)能够使量表的某些部分传达出特定含义。

一个区段代表量表的一个子范围,在绘制处于该子范围之内的量表各部分(线条、弧线、刻度和标签)时,其样式(就如同层叠样式表那样)具有优先级。

如果量表的某个部分处于两个或更多区段的范围内(即这些区段相互重叠),那么属于最后添加的那个区段的样式属性,相较于涉及该部分的其他区段的相同样式属性而言,具有更高的优先级。

Creating Sections(创建区段)

显示原文

A Section is created using lv_scale_add_section(scale), which returns a pointer to a lv_scale_section_t object. This creates a Section with range [0..0] and no Styles added to it, which ensures that Section will not be drawn yet: it needs both a range inside the Scale's range and at least one Style added to it before it will be used in drawing the Scale.

Next, set the range using lv_scale_section_set_range(section, min, max) where min and max are the Section's boundary values that should normally be within the Scale's value range. (If they are only partially within the Scale's range, the Scale will only use that portion of the Section that overlaps the Scale's range. If a Section's range is not within the Scale's range at all, it will not be used in drawing. That can be useful to temporarily "disable" a Section, e.g. lv_scale_section_set_range(section, 0, -1).)


使用 :cpp:expr:`lv_scale_add_section(scale)`来创建一个区段(Section),该函数会返回一个指向 :cpp:type:`lv_scale_section_t`对象的指针。这样创建出来的区段其范围是 [0..0],并且没有添加任何样式,这确保了该区段暂时不会被绘制出来:在它能够用于绘制量表之前,既需要有处于量表取值范围内的范围值,又需要至少添加一个:ref:`Style <styles>`才行。

接下来,使用 lv_scale_section_set_range(section, min, max)`来设置范围,其中 ``min`max 是该区段的边界值,通常它们应当处于量表的取值范围之内。(如果它们只是部分处于量表的取值范围之内,那么量表将只会使用该区段与量表取值范围相重叠的那部分。如果一个区段的范围完全不在量表的取值范围之内,那么它在绘制时将不会被使用。这对于临时 “禁用” 一个区段来说是很有用的,例如 lv_scale_section_set_range(section, 0, -1).)

Styling Sections(设置区段样式)

显示原文

You set a Section's Style properties by creating a lv_style_t object for each "section" you want to appear different than the parent Scale. Add style properties as is documented in style_initialize.

You attach each lv_style_t object to each Section it will apply to using lv_scale_section_set_style(section, PART, style_pointer), where:

  • style_pointer should point to the contents of a global or static variable (can be dynamically-allocated), since it needs to remain valid through the life of the Scale; and

  • PART indicates which single PART of the parent Scale it will apply to, namely LV_PART_MAIN, LV_PART_ITEMS or LV_PART_INDICATOR.

Unlike adding normal styles to Widgets, you cannot combine PARTs by bit-wise OR-ing the PART values together to get the style to apply to more than one part. However, you can do something like this to accomplish the same thing:

static lv_style_t  tick_style;
lv_style_init(&tick_style);
lv_style_set_line_color(&tick_style, lv_palette_darken(LV_PALETTE_RED, 3));
lv_scale_section_set_style(section, LV_PART_ITEMS, &tick_style);
lv_scale_section_set_style(section, LV_PART_INDICATOR, &tick_style);

to get that one Style object to apply to both major and minor ticks.

lv_style_t objects can be shared among Sections and among PARTs, but unlike normal Styles added to a Widget, a Section can only have 1 style per PART. Thus, doing this:

lv_scale_section_set_style(section, LV_PART_INDICATOR, &tick_style_1);
lv_scale_section_set_style(section, LV_PART_INDICATOR, &tick_style_2);

replaces tick_style_1 with tick_style_2 for part LV_PART_INDICATOR rather than adding to it.


你可以通过为每个想要呈现出与父量表不同外观的 “区段” 创建一个 :cpp:type:`lv_style_t`对象来设置区段的样式属性。按照在 :ref:`style_initialize`中记录的方式添加样式属性。

你可以使用 lv_scale_section_set_style(section, PART, style_pointer)`将每个 :cpp:type:`lv_style_t 类型的对象附加到它要应用的每个区段上,其中:

  • style_pointer 应当指向一个全局或静态变量(也可以是动态分配的)的内容,因为在量表的整个生命周期内它都需要保持有效;并且

  • PART 指明了它将应用于父量表的哪个:ref:PART <lv_scale_parts_and_styles>`部分,即 :cpp:enumerator:`LV_PART_MAINLV_PART_ITEMS`或 :cpp:enumerator:`LV_PART_INDICATOR

与向部件添加常规样式不同的是,你不能通过按位或(bit-wise OR-ing)这些部分的值来组合部分,以使样式应用于多个部分。不过,你可以像下面这样做来实现相同的效果:

static lv_style_t  tick_style;
lv_style_init(&tick_style);
lv_style_set_line_color(&tick_style, lv_palette_darken(LV_PALETTE_RED, 3));
lv_scale_section_set_style(section, LV_PART_ITEMS, &tick_style);
lv_scale_section_set_style(section, LV_PART_INDICATOR, &tick_style);

这样就能让这个样式对象同时应用于主刻度和次刻度了。

lv_style_t 类型的对象可以在区段之间以及部分之间共享,但是与添加到部件的常规样式不同,一个区段对于每个部分只能有一个样式。因此,像下面这样做:

lv_scale_section_set_style(section, LV_PART_INDICATOR, &tick_style_1);
lv_scale_section_set_style(section, LV_PART_INDICATOR, &tick_style_2);

会用 tick_style_2 替换掉针对 LV_PART_INDICATOR 部分的 tick_style_1,而不是在其基础上添加。

Useful Style Properties for Sections(对于区段(Section)有用的样式属性)

显示原文

The Style properties that are used during Scale drawing (and are thus useful) are:


在量表绘制过程中会用到的样式属性(因而很有用)如下:

Events(事件)

显示原文

No special events are sent by Scale Widgets.

Further Reading

Learn more about Base-Widget Events emitted by all Widgets.

Learn more about Events(事件).


量表部件(Scale Widgets)不会发送特殊事件。

了解更多有关所有部件都会发出的 :ref:`lv_obj_events`的内容。

了解更多有关 :ref:`events`的内容。 .. _lv_scale_keys:

Keys

显示原文

No Keys are processed by Scale Widgets.

Further Reading

Learn more about Keys(按键).


量表部件(Scale Widgets)不处理 *按键*操作。

了解更多有关 :ref:`indev_keys`的内容。

Example

A simple horizontal scale

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

/**
 * A simple horizontal scale
 */
void lv_example_scale_1(void)
{
    lv_obj_t * scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale, lv_pct(80), 100);
    lv_scale_set_mode(scale, LV_SCALE_MODE_HORIZONTAL_BOTTOM);
    lv_obj_center(scale);

    lv_scale_set_label_show(scale, true);

    lv_scale_set_total_tick_count(scale, 31);
    lv_scale_set_major_tick_every(scale, 5);

    lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale, 10, 40);
}

#endif

An vertical scale with section and custom styling

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

/**
 * An vertical scale with section and custom styling
 */
void lv_example_scale_2(void)
{
    lv_obj_t * scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale, 60, 200);
    lv_scale_set_label_show(scale, true);
    lv_scale_set_mode(scale, LV_SCALE_MODE_VERTICAL_RIGHT);
    lv_obj_center(scale);

    lv_scale_set_total_tick_count(scale, 21);
    lv_scale_set_major_tick_every(scale, 5);

    lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);
    lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);
    lv_scale_set_range(scale, 0, 100);

    static const char * custom_labels[] = {"0 °C", "25 °C", "50 °C", "75 °C", "100 °C", NULL};
    lv_scale_set_text_src(scale, custom_labels);

    static lv_style_t indicator_style;
    lv_style_init(&indicator_style);

    /* Label style properties */
    lv_style_set_text_font(&indicator_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&indicator_style, lv_palette_darken(LV_PALETTE_BLUE, 3));

    /* Major tick properties */
    lv_style_set_line_color(&indicator_style, lv_palette_darken(LV_PALETTE_BLUE, 3));
    lv_style_set_width(&indicator_style, 10U);      /*Tick length*/
    lv_style_set_line_width(&indicator_style, 2U);  /*Tick width*/
    lv_obj_add_style(scale, &indicator_style, LV_PART_INDICATOR);

    static lv_style_t minor_ticks_style;
    lv_style_init(&minor_ticks_style);
    lv_style_set_line_color(&minor_ticks_style, lv_palette_lighten(LV_PALETTE_BLUE, 2));
    lv_style_set_width(&minor_ticks_style, 5U);         /*Tick length*/
    lv_style_set_line_width(&minor_ticks_style, 2U);    /*Tick width*/
    lv_obj_add_style(scale, &minor_ticks_style, LV_PART_ITEMS);

    static lv_style_t main_line_style;
    lv_style_init(&main_line_style);
    /* Main line properties */
    lv_style_set_line_color(&main_line_style, lv_palette_darken(LV_PALETTE_BLUE, 3));
    lv_style_set_line_width(&main_line_style, 2U); // Tick width
    lv_obj_add_style(scale, &main_line_style, LV_PART_MAIN);

    /* Add a section */
    static lv_style_t section_minor_tick_style;
    static lv_style_t section_label_style;
    static lv_style_t section_main_line_style;

    lv_style_init(&section_label_style);
    lv_style_init(&section_minor_tick_style);
    lv_style_init(&section_main_line_style);

    /* Label style properties */
    lv_style_set_text_font(&section_label_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&section_label_style, lv_palette_darken(LV_PALETTE_RED, 3));

    lv_style_set_line_color(&section_label_style, lv_palette_darken(LV_PALETTE_RED, 3));
    lv_style_set_line_width(&section_label_style, 5U); /*Tick width*/

    lv_style_set_line_color(&section_minor_tick_style, lv_palette_lighten(LV_PALETTE_RED, 2));
    lv_style_set_line_width(&section_minor_tick_style, 4U); /*Tick width*/

    /* Main line properties */
    lv_style_set_line_color(&section_main_line_style, lv_palette_darken(LV_PALETTE_RED, 3));
    lv_style_set_line_width(&section_main_line_style, 4U); /*Tick width*/

    /* Configure section styles */
    lv_scale_section_t * section = lv_scale_add_section(scale);
    lv_scale_section_set_range(section, 75, 100);
    lv_scale_section_set_style(section, LV_PART_INDICATOR, &section_label_style);
    lv_scale_section_set_style(section, LV_PART_ITEMS, &section_minor_tick_style);
    lv_scale_section_set_style(section, LV_PART_MAIN, &section_main_line_style);

    lv_obj_set_style_bg_color(scale, lv_palette_main(LV_PALETTE_BLUE_GREY), 0);
    lv_obj_set_style_bg_opa(scale, LV_OPA_50, 0);
    lv_obj_set_style_pad_left(scale, 8, 0);
    lv_obj_set_style_radius(scale, 8, 0);
    lv_obj_set_style_pad_ver(scale, 20, 0);
}

#endif

A simple round scale

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

LV_IMAGE_DECLARE(img_hand);

lv_obj_t * needle_line;
lv_obj_t * needle_img;

static void set_needle_line_value(void * obj, int32_t v)
{
    lv_scale_set_line_needle_value(obj, needle_line, 60, v);
}

static void set_needle_img_value(void * obj, int32_t v)
{
    lv_scale_set_image_needle_value(obj, needle_img, v);
}

/**
 * A simple round scale
 */
void lv_example_scale_3(void)
{
    lv_obj_t * scale_line = lv_scale_create(lv_screen_active());

    lv_obj_set_size(scale_line, 150, 150);
    lv_scale_set_mode(scale_line, LV_SCALE_MODE_ROUND_INNER);
    lv_obj_set_style_bg_opa(scale_line, LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(scale_line, lv_palette_lighten(LV_PALETTE_RED, 5), 0);
    lv_obj_set_style_radius(scale_line, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_style_clip_corner(scale_line, true, 0);
    lv_obj_align(scale_line, LV_ALIGN_LEFT_MID, LV_PCT(2), 0);

    lv_scale_set_label_show(scale_line, true);

    lv_scale_set_total_tick_count(scale_line, 31);
    lv_scale_set_major_tick_every(scale_line, 5);

    lv_obj_set_style_length(scale_line, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale_line, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale_line, 10, 40);

    lv_scale_set_angle_range(scale_line, 270);
    lv_scale_set_rotation(scale_line, 135);

    needle_line = lv_line_create(scale_line);

    lv_obj_set_style_line_width(needle_line, 6, LV_PART_MAIN);
    lv_obj_set_style_line_rounded(needle_line, true, LV_PART_MAIN);

    lv_anim_t anim_scale_line;
    lv_anim_init(&anim_scale_line);
    lv_anim_set_var(&anim_scale_line, scale_line);
    lv_anim_set_exec_cb(&anim_scale_line, set_needle_line_value);
    lv_anim_set_duration(&anim_scale_line, 1000);
    lv_anim_set_repeat_count(&anim_scale_line, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_playback_duration(&anim_scale_line, 1000);
    lv_anim_set_values(&anim_scale_line, 10, 40);
    lv_anim_start(&anim_scale_line);

    lv_obj_t * scale_img = lv_scale_create(lv_screen_active());

    lv_obj_set_size(scale_img, 150, 150);
    lv_scale_set_mode(scale_img, LV_SCALE_MODE_ROUND_INNER);
    lv_obj_set_style_bg_opa(scale_img, LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(scale_img, lv_palette_lighten(LV_PALETTE_RED, 5), 0);
    lv_obj_set_style_radius(scale_img, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_style_clip_corner(scale_img, true, 0);
    lv_obj_align(scale_img, LV_ALIGN_RIGHT_MID, LV_PCT(-2), 0);

    lv_scale_set_label_show(scale_img, true);

    lv_scale_set_total_tick_count(scale_img, 31);
    lv_scale_set_major_tick_every(scale_img, 5);

    lv_obj_set_style_length(scale_img, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale_img, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale_img, 10, 40);

    lv_scale_set_angle_range(scale_img, 270);
    lv_scale_set_rotation(scale_img, 135);

    /* image must point to the right. E.g. -O------>*/
    needle_img = lv_image_create(scale_img);
    lv_image_set_src(needle_img, &img_hand);
    lv_obj_align(needle_img, LV_ALIGN_CENTER, 47, -2);
    lv_image_set_pivot(needle_img, 3, 4);

    lv_anim_t anim_scale_img;
    lv_anim_init(&anim_scale_img);
    lv_anim_set_var(&anim_scale_img, scale_img);
    lv_anim_set_exec_cb(&anim_scale_img, set_needle_img_value);
    lv_anim_set_duration(&anim_scale_img, 1000);
    lv_anim_set_repeat_count(&anim_scale_img, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_playback_duration(&anim_scale_img, 1000);
    lv_anim_set_values(&anim_scale_img, 10, 40);
    lv_anim_start(&anim_scale_img);
}

#endif

A round scale with section and custom styling

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

/**
 * A round scale with section and custom styling
 */
void lv_example_scale_4(void)
{
    lv_obj_t * scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale, 150, 150);
    lv_scale_set_label_show(scale, true);
    lv_scale_set_mode(scale, LV_SCALE_MODE_ROUND_OUTER);
    lv_obj_center(scale);

    lv_scale_set_total_tick_count(scale, 21);
    lv_scale_set_major_tick_every(scale, 5);

    lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale, 0, 100);

    static const char * custom_labels[] = {"0 °C", "25 °C", "50 °C", "75 °C", "100 °C", NULL};
    lv_scale_set_text_src(scale, custom_labels);

    static lv_style_t indicator_style;
    lv_style_init(&indicator_style);

    /* Label style properties */
    lv_style_set_text_font(&indicator_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&indicator_style, lv_palette_darken(LV_PALETTE_BLUE, 3));

    /* Major tick properties */
    lv_style_set_line_color(&indicator_style, lv_palette_darken(LV_PALETTE_BLUE, 3));
    lv_style_set_width(&indicator_style, 10U);      /*Tick length*/
    lv_style_set_line_width(&indicator_style, 2U);  /*Tick width*/
    lv_obj_add_style(scale, &indicator_style, LV_PART_INDICATOR);

    static lv_style_t minor_ticks_style;
    lv_style_init(&minor_ticks_style);
    lv_style_set_line_color(&minor_ticks_style, lv_palette_lighten(LV_PALETTE_BLUE, 2));
    lv_style_set_width(&minor_ticks_style, 5U);         /*Tick length*/
    lv_style_set_line_width(&minor_ticks_style, 2U);    /*Tick width*/
    lv_obj_add_style(scale, &minor_ticks_style, LV_PART_ITEMS);

    static lv_style_t main_line_style;
    lv_style_init(&main_line_style);
    /* Main line properties */
    lv_style_set_arc_color(&main_line_style, lv_palette_darken(LV_PALETTE_BLUE, 3));
    lv_style_set_arc_width(&main_line_style, 2U); /*Tick width*/
    lv_obj_add_style(scale, &main_line_style, LV_PART_MAIN);

    /* Add a section */
    static lv_style_t section_minor_tick_style;
    static lv_style_t section_label_style;
    static lv_style_t section_main_line_style;

    lv_style_init(&section_label_style);
    lv_style_init(&section_minor_tick_style);
    lv_style_init(&section_main_line_style);

    /* Label style properties */
    lv_style_set_text_font(&section_label_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&section_label_style, lv_palette_darken(LV_PALETTE_RED, 3));

    lv_style_set_line_color(&section_label_style, lv_palette_darken(LV_PALETTE_RED, 3));
    lv_style_set_line_width(&section_label_style, 5U); /*Tick width*/

    lv_style_set_line_color(&section_minor_tick_style, lv_palette_lighten(LV_PALETTE_RED, 2));
    lv_style_set_line_width(&section_minor_tick_style, 4U); /*Tick width*/

    /* Main line properties */
    lv_style_set_arc_color(&section_main_line_style, lv_palette_darken(LV_PALETTE_RED, 3));
    lv_style_set_arc_width(&section_main_line_style, 4U); /*Tick width*/

    /* Configure section styles */
    lv_scale_section_t * section = lv_scale_add_section(scale);
    lv_scale_section_set_range(section, 75, 100);
    lv_scale_section_set_style(section, LV_PART_INDICATOR, &section_label_style);
    lv_scale_section_set_style(section, LV_PART_ITEMS, &section_minor_tick_style);
    lv_scale_section_set_style(section, LV_PART_MAIN, &section_main_line_style);
}

#endif

A scale with section and custom styling

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

/**
 * An scale with section and custom styling
 */
void lv_example_scale_5(void)
{
    lv_obj_t * scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale, lv_display_get_horizontal_resolution(NULL) / 2, lv_display_get_vertical_resolution(NULL) / 2);
    lv_scale_set_label_show(scale, true);

    lv_scale_set_total_tick_count(scale, 10);
    lv_scale_set_major_tick_every(scale, 5);

    lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale, 25, 35);

    static const char * custom_labels[3] = {"One", "Two", NULL};
    lv_scale_set_text_src(scale, custom_labels);

    static lv_style_t indicator_style;
    lv_style_init(&indicator_style);
    /* Label style properties */
    lv_style_set_text_font(&indicator_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&indicator_style, lv_color_hex(0xff00ff));
    /* Major tick properties */
    lv_style_set_line_color(&indicator_style, lv_color_hex(0x00ff00));
    lv_style_set_width(&indicator_style, 10U); // Tick length
    lv_style_set_line_width(&indicator_style, 2U); // Tick width
    lv_obj_add_style(scale, &indicator_style, LV_PART_INDICATOR);

    static lv_style_t minor_ticks_style;
    lv_style_init(&minor_ticks_style);
    lv_style_set_line_color(&minor_ticks_style, lv_color_hex(0xff0000));
    lv_style_set_width(&minor_ticks_style, 5U); // Tick length
    lv_style_set_line_width(&minor_ticks_style, 2U); // Tick width
    lv_obj_add_style(scale, &minor_ticks_style, LV_PART_ITEMS);

    static lv_style_t main_line_style;
    lv_style_init(&main_line_style);
    /* Main line properties */
    lv_style_set_line_color(&main_line_style, lv_color_hex(0x0000ff));
    lv_style_set_line_width(&main_line_style, 2U); // Tick width
    lv_obj_add_style(scale, &main_line_style, LV_PART_MAIN);

    lv_obj_center(scale);

    /* Add a section */
    static lv_style_t section_minor_tick_style;
    static lv_style_t section_label_style;

    lv_style_init(&section_label_style);
    lv_style_init(&section_minor_tick_style);

    /* Label style properties */
    lv_style_set_text_font(&section_label_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&section_label_style, lv_color_hex(0xff0000));
    lv_style_set_text_letter_space(&section_label_style, 10);
    lv_style_set_text_opa(&section_label_style, LV_OPA_50);

    lv_style_set_line_color(&section_label_style, lv_color_hex(0xff0000));
    // lv_style_set_width(&section_label_style, 20U); // Tick length
    lv_style_set_line_width(&section_label_style, 5U); // Tick width

    lv_style_set_line_color(&section_minor_tick_style, lv_color_hex(0x0000ff));
    // lv_style_set_width(&section_label_style, 20U); // Tick length
    lv_style_set_line_width(&section_minor_tick_style, 4U); // Tick width

    /* Configure section styles */
    lv_scale_section_t * section = lv_scale_add_section(scale);
    lv_scale_section_set_range(section, 25, 30);
    lv_scale_section_set_style(section, LV_PART_INDICATOR, &section_label_style);
    lv_scale_section_set_style(section, LV_PART_ITEMS, &section_minor_tick_style);
}

#endif

A round scale with multiple needles, resembling a clock

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

#if LV_USE_FLOAT
    #define my_PRIprecise "f"
#else
    #define my_PRIprecise LV_PRId32
#endif

static lv_obj_t * scale;
static lv_obj_t * minute_hand;
static lv_obj_t * hour_hand;
static lv_point_precise_t minute_hand_points[2];
static int32_t hour;
static int32_t minute;

static void timer_cb(lv_timer_t * timer)
{
    LV_UNUSED(timer);

    minute++;
    if(minute > 59) {
        minute = 0;
        hour++;
        if(hour > 11) {
            hour = 0;
        }
    }

    /**
     * the scale will store the needle line points in the existing
     * point array if one was set with `lv_line_set_points_mutable`.
     * Otherwise, it will allocate the needle line points.
     */

    /* the scale will store the minute hand line points in `minute_hand_points` */
    lv_scale_set_line_needle_value(scale, minute_hand, 60, minute);
    /* log the points that were stored in the array */
    LV_LOG_USER(
        "minute hand points - "
        "0: (%" my_PRIprecise ", %" my_PRIprecise "), "
        "1: (%" my_PRIprecise ", %" my_PRIprecise ")",
        minute_hand_points[0].x, minute_hand_points[0].y,
        minute_hand_points[1].x, minute_hand_points[1].y
    );

    /* the scale will allocate the hour hand line points */
    lv_scale_set_line_needle_value(scale, hour_hand, 40, hour * 5 + (minute / 12));
}

/**
 * A round scale with multiple needles, resembling a clock
 */
void lv_example_scale_6(void)
{
    scale = lv_scale_create(lv_screen_active());

    lv_obj_set_size(scale, 150, 150);
    lv_scale_set_mode(scale, LV_SCALE_MODE_ROUND_INNER);
    lv_obj_set_style_bg_opa(scale, LV_OPA_60, 0);
    lv_obj_set_style_bg_color(scale, lv_color_black(), 0);
    lv_obj_set_style_radius(scale, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_style_clip_corner(scale, true, 0);
    lv_obj_center(scale);

    lv_scale_set_label_show(scale, true);

    lv_scale_set_total_tick_count(scale, 61);
    lv_scale_set_major_tick_every(scale, 5);

    static const char * hour_ticks[] = {"12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", NULL};
    lv_scale_set_text_src(scale, hour_ticks);

    static lv_style_t indicator_style;
    lv_style_init(&indicator_style);

    /* Label style properties */
    lv_style_set_text_font(&indicator_style, LV_FONT_DEFAULT);
    lv_style_set_text_color(&indicator_style, lv_palette_main(LV_PALETTE_YELLOW));

    /* Major tick properties */
    lv_style_set_line_color(&indicator_style, lv_palette_main(LV_PALETTE_YELLOW));
    lv_style_set_length(&indicator_style, 8); /* tick length */
    lv_style_set_line_width(&indicator_style, 2); /* tick width */
    lv_obj_add_style(scale, &indicator_style, LV_PART_INDICATOR);

    /* Minor tick properties */
    static lv_style_t minor_ticks_style;
    lv_style_init(&minor_ticks_style);
    lv_style_set_line_color(&minor_ticks_style, lv_palette_main(LV_PALETTE_YELLOW));
    lv_style_set_length(&minor_ticks_style, 6); /* tick length */
    lv_style_set_line_width(&minor_ticks_style, 2); /* tick width */
    lv_obj_add_style(scale, &minor_ticks_style, LV_PART_ITEMS);

    /* Main line properties */
    static lv_style_t main_line_style;
    lv_style_init(&main_line_style);
    lv_style_set_arc_color(&main_line_style, lv_color_black());
    lv_style_set_arc_width(&main_line_style, 5);
    lv_obj_add_style(scale, &main_line_style, LV_PART_MAIN);

    lv_scale_set_range(scale, 0, 60);

    lv_scale_set_angle_range(scale, 360);
    lv_scale_set_rotation(scale, 270);

    minute_hand = lv_line_create(scale);
    lv_line_set_points_mutable(minute_hand, minute_hand_points, 2);

    lv_obj_set_style_line_width(minute_hand, 3, 0);
    lv_obj_set_style_line_rounded(minute_hand, true, 0);
    lv_obj_set_style_line_color(minute_hand, lv_color_white(), 0);

    hour_hand = lv_line_create(scale);

    lv_obj_set_style_line_width(hour_hand, 5, 0);
    lv_obj_set_style_line_rounded(hour_hand, true, 0);
    lv_obj_set_style_line_color(hour_hand, lv_palette_main(LV_PALETTE_RED), 0);

    hour = 11;
    minute = 5;
    lv_timer_t * timer = lv_timer_create(timer_cb, 250, NULL);
    lv_timer_ready(timer);
}

#endif

Customizing scale major tick label color with LV_EVENT_DRAW_TASK_ADDED event

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

#include "../../../src/lvgl_private.h" //To expose the fields of lv_draw_task_t

static void draw_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);
    lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
    lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
    lv_draw_label_dsc_t * label_draw_dsc = lv_draw_task_get_label_dsc(draw_task);
    if(base_dsc->part == LV_PART_INDICATOR) {
        if(label_draw_dsc) {
            const lv_color_t color_idx[7] = {
                lv_palette_main(LV_PALETTE_RED),
                lv_palette_main(LV_PALETTE_ORANGE),
                lv_palette_main(LV_PALETTE_YELLOW),
                lv_palette_main(LV_PALETTE_GREEN),
                lv_palette_main(LV_PALETTE_CYAN),
                lv_palette_main(LV_PALETTE_BLUE),
                lv_palette_main(LV_PALETTE_PURPLE),
            };
            uint8_t major_tick = lv_scale_get_major_tick_every(obj);
            label_draw_dsc->color = color_idx[base_dsc->id1 / major_tick];

            /*Free the previously allocated text if needed*/
            if(label_draw_dsc->text_local) lv_free((void *)label_draw_dsc->text);

            /*Malloc the text and set text_local as 1 to make LVGL automatically free the text.
             * (Local texts are malloc'd internally by LVGL. Mimic this behavior here too)*/
            char tmp_buffer[20] = {0}; /* Big enough buffer */
            lv_snprintf(tmp_buffer, sizeof(tmp_buffer), "%.1f", base_dsc->id2 * 1.0f);
            label_draw_dsc->text = lv_strdup(tmp_buffer);
            label_draw_dsc->text_local = 1;

            lv_point_t size;
            lv_text_get_size(&size, label_draw_dsc->text, label_draw_dsc->font, 0, 0, 1000, LV_TEXT_FLAG_NONE);
            int32_t new_w = size.x;
            int32_t old_w = lv_area_get_width(&draw_task->area);

            /* Distribute the new size equally on both sides */
            draw_task->area.x1 -= (new_w - old_w) / 2;
            draw_task->area.x2 += ((new_w - old_w) + 1) / 2;  /* +1 for rounding */

        }
    }
}

/**
 * Customizing scale major tick label color with `LV_EVENT_DRAW_TASK_ADDED` event
 */
void lv_example_scale_7(void)
{
    lv_obj_t * scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale, lv_pct(80), 100);
    lv_scale_set_mode(scale, LV_SCALE_MODE_HORIZONTAL_BOTTOM);
    lv_obj_center(scale);

    lv_scale_set_label_show(scale, true);

    lv_scale_set_total_tick_count(scale, 31);
    lv_scale_set_major_tick_every(scale, 5);

    lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale, 10, 40);

    lv_obj_add_event_cb(scale, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
    lv_obj_add_flag(scale, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
}

#endif

A round scale with labels rotated and translated

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES


/**
 * A simple round scale with label/tick translation
 */
void lv_example_scale_8(void)
{
    lv_obj_t * scale_line = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale_line, 150, 150);
    lv_scale_set_mode(scale_line, LV_SCALE_MODE_ROUND_INNER);
    lv_obj_set_style_bg_opa(scale_line, LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(scale_line, lv_palette_lighten(LV_PALETTE_RED, 5), 0);
    lv_obj_set_style_radius(scale_line, LV_RADIUS_CIRCLE, 0);
    lv_obj_align(scale_line, LV_ALIGN_LEFT_MID, LV_PCT(2), 0);

    /*Set the texts' and major ticks' style (make the texts rotated)*/
    lv_obj_set_style_transform_rotation(scale_line, LV_SCALE_LABEL_ROTATE_MATCH_TICKS | LV_SCALE_LABEL_ROTATE_KEEP_UPRIGHT,
                                        LV_PART_INDICATOR);
    lv_obj_set_style_translate_x(scale_line, 10, LV_PART_INDICATOR);
    lv_obj_set_style_length(scale_line, 15, LV_PART_INDICATOR);
    lv_obj_set_style_radial_offset(scale_line, 10, LV_PART_INDICATOR);

    /*Set the style of the minor ticks*/
    lv_obj_set_style_length(scale_line, 10, LV_PART_ITEMS);
    lv_obj_set_style_radial_offset(scale_line, 5, LV_PART_ITEMS);
    lv_obj_set_style_line_opa(scale_line, LV_OPA_50, LV_PART_ITEMS);

    lv_scale_set_label_show(scale_line, true);

    lv_scale_set_total_tick_count(scale_line, 31);
    lv_scale_set_major_tick_every(scale_line, 5);

    lv_scale_set_range(scale_line, 10, 40);

    lv_scale_set_angle_range(scale_line, 270);
    lv_scale_set_rotation(scale_line, 135);

    lv_obj_t * needle_line = lv_line_create(scale_line);

    lv_obj_set_style_line_width(needle_line, 3, LV_PART_MAIN);
    lv_obj_set_style_line_rounded(needle_line, true, LV_PART_MAIN);
    lv_scale_set_line_needle_value(scale_line, needle_line, 60, 33);
}

#endif

A horizontal scale with labels rotated and translated

#include "../../lv_examples.h"
#if LV_USE_SCALE && LV_BUILD_EXAMPLES

/**
 * A simple horizontal scale with transforms
 */
void lv_example_scale_9(void)
{
    lv_obj_t * scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(scale, 200, 100);
    lv_scale_set_mode(scale, LV_SCALE_MODE_HORIZONTAL_BOTTOM);
    lv_obj_center(scale);

    lv_scale_set_label_show(scale, true);
    lv_obj_set_style_transform_rotation(scale, 450, LV_PART_INDICATOR);
    lv_obj_set_style_length(scale, 30, LV_PART_INDICATOR);
    lv_obj_set_style_translate_x(scale, 5, LV_PART_INDICATOR);

    lv_scale_set_total_tick_count(scale, 31);
    lv_scale_set_major_tick_every(scale, 5);

    lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);
    lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);
    lv_scale_set_range(scale, 10, 40);
}

#endif

API

Scale (标尺)(lv_scale) .. Autogenerated

lv_types.h

lv_scale.h