Development docs. Unreleased and may change.Switch to Release v9.6.0

Subjects

Learn more about Subjects.

Edit on GitHub

A Subject is a value you can observe. When you change it, every Observer attached to it is notified automatically. A Subject can hold an integer, a float, a string, a pointer, a color, or a group of other Subjects.

Creating a Subject

lv_subject_create() allocates a Subject of the requested type and returns a pointer to it. Keep that pointer in a static or global variable; it has to stay alive as long as anything observes the Subject.

 
static lv_subject_t * temperature;
temperature = lv_subject_create(LV_SUBJECT_TYPE_INT);
lv_subject_set_int(temperature, 20);            /* integer, starts at 20 */

A newly created Subject starts from a neutral value: 0 for int and float, NULL for pointer, black for color, an empty string for string, and an empty list for group. Set the initial value with the matching lv_subject_set_...() function, as above.

The available types are LV_SUBJECT_TYPE_INT, LV_SUBJECT_TYPE_FLOAT (requires LV_USE_FLOAT), LV_SUBJECT_TYPE_STRING, LV_SUBJECT_TYPE_POINTER, LV_SUBJECT_TYPE_COLOR and LV_SUBJECT_TYPE_GROUP.

Strings need a buffer to live in (and an optional second buffer to remember the previous value). The buffers are supplied with

lv_subject_set_string_buffer_static()

and must out-live the Subject:

 
static lv_subject_t * title;
static char buf[32];
static char prev_buf[32];
title = lv_subject_create(LV_SUBJECT_TYPE_STRING);
lv_subject_set_string_buffer_static(title, buf, prev_buf, sizeof(buf));
lv_subject_set_string(title, "Hello");

Deleting a Subject

lv_subject_delete() removes every Observer from a Subject, deletes the Widget bindings attached to it, and frees it. It accepts NULL, so it is safe to call on a pointer that was never created.

 
lv_subject_delete(temperature);
temperature = NULL;

Any Subject still alive at lv_deinit() is deleted automatically, so a Subject that lives for the whole run of the application doesn't have to be deleted by hand.

Reading and Writing the Value

Write a value with lv_subject_set_...() (e.g. lv_subject_set_int).

Most value types notify Observers only when the value changes, however pointer Subjects notify on every set, group Subjects notify when their members or the group list changes, and strings when the previous buffer is also set.

Read the current value back with lv_subject_get_...() (e.g. lv_subject_get_int):

 
lv_subject_set_int(temperature, 25);            /* notifies observers */
int32_t t = lv_subject_get_int(temperature);    /* -> 25 */

Strings are copied into the Subject's own buffer, so update them with lv_subject_set_string():

 
lv_subject_set_string(title, "Settings");

Every type (except groups) also has a lv_subject_get_previous_...() function (e.g. lv_subject_get_previous_int) that returns the value from before the last change, which is handy when a callback needs to compare old and new.

Limiting the Range

Integer and float Subjects can be clamped. Out-of-range values are pulled back in before the Observers are notified:

 
lv_subject_set_min_value_int(temperature, 0);
lv_subject_set_max_value_int(temperature, 100);

Set the limits before the first value: lv_subject_set_int() clamps to them.

Grouping Several Subjects

Sometimes one thing depends on several values at once. A group Subject ties them together, so an Observer fires whenever any member changes.

The list of members is passed with lv_subject_set_group_list_static(). The array is not copied, so it must out-live the group Subject:

 
static lv_subject_t * list[3];
static lv_subject_t * measurement;

list[0] = mode;
list[1] = value;
list[2] = unit;

measurement = lv_subject_create(LV_SUBJECT_TYPE_GROUP);
lv_subject_set_group_list_static(measurement, list, 3);

In the callback, reach the members with lv_subject_get_group_element():

 
static void measurement_cb(lv_observer_t * observer, lv_subject_t * subject)
{
    lv_obj_t * label = lv_observer_get_target(observer);
    int32_t mode      = lv_subject_get_int(lv_subject_get_group_element(subject, 0));
    int32_t value     = lv_subject_get_int(lv_subject_get_group_element(subject, 1));
    const char * unit = lv_subject_get_pointer(lv_subject_get_group_element(subject, 2));
    lv_label_set_text_fmt(label, "%s: %d %s", mode ? "Current" : "Voltage", value, unit);
}

The group subject needs to be deinitialized before any of the subjects it points to.

Changing a Subject from the UI

Instead of writing an event handler, you can let a Widget update a Subject directly. For example, toggle an integer between 0 and 1 when a button is clicked:

 
lv_obj_add_subject_toggle_event(button, enabled, LV_EVENT_CLICKED);

Other ready-made actions:

Do not delete a Subject while these events remain attached as their callbacks saved a pointer to the Subject.

Last updated on

On this page