Subjects
Learn more about Subjects.
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:
-
lv_obj_add_subject_increment_event(obj, subject, trigger, step)addsstepto the value (use a negativestepto subtract). It returns a descriptor you can adjust further withlv_obj_set_subject_increment_event_min_value(),lv_obj_set_subject_increment_event_max_value()andlv_obj_set_subject_increment_event_rollover(). lv_obj_add_subject_set_int_event(),lv_obj_add_subject_set_float_event()(requiresLV_USE_FLOAT) andlv_obj_add_subject_set_string_event()write a fixed value on the trigger.
Do not delete a Subject while these events remain attached as their callbacks saved a pointer to the Subject.
Last updated on