# Subjects (/main-modules/data_binding/subjects)



A **Subject** is a value you can observe. When you change it, every
[Observer](/main-modules/data_binding/observers) 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 [#creating-a-subject]

<ApiLink name="lv_subject_create" display="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.

```c title=" " lineNumbers=1
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
<ApiLink name="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

<ApiLink name="lv_subject_set_string_buffer_static" display="lv_subject_set_string_buffer_static()" />

and must out-live the Subject:

```c title=" " lineNumbers=1
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 [#deleting-a-subject]

<ApiLink name="lv_subject_delete" display="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.

```c title=" " lineNumbers=1
lv_subject_delete(temperature);
temperature = NULL;
```

Any Subject still alive at <ApiLink name="lv_deinit" display="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 [#reading-and-writing-the-value]

Write a value with `lv_subject_set_...()` (e.g. <ApiLink name="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. <ApiLink name="lv_subject_get_int" />):

```c title=" " lineNumbers=1
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
<ApiLink name="lv_subject_set_string" display="lv_subject_set_string()" />:

```c title=" " lineNumbers=1
lv_subject_set_string(title, "Settings");
```

Every type (except groups) also has a `lv_subject_get_previous_...()` function (e.g.
<ApiLink name="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 [#limiting-the-range]

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

```c title=" " lineNumbers=1
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 [#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
<ApiLink name="lv_subject_set_group_list_static" display="lv_subject_set_group_list_static()" />.
The array is not copied, so it must out-live the group Subject:

```c title=" " lineNumbers=1
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
<ApiLink name="lv_subject_get_group_element" display="lv_subject_get_group_element()" />:

```c title=" " lineNumbers=1
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);
}
```

<Callout type="warn">
  The group subject needs to be deinitialized before any of the subjects it points to.
</Callout>

Changing a Subject from the UI [#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:

```c title=" " lineNumbers=1
lv_obj_add_subject_toggle_event(button, enabled, LV_EVENT_CLICKED);
```

Other ready-made actions:

* <ApiLink name="lv_obj_add_subject_increment_event" display="lv_obj_add_subject_increment_event(obj, subject, trigger, step)" />
  adds `step` to the value (use a negative `step` to subtract). It returns a
  descriptor you can adjust further with
  <ApiLink name="lv_obj_set_subject_increment_event_min_value" display="lv_obj_set_subject_increment_event_min_value()" />,
  <ApiLink name="lv_obj_set_subject_increment_event_max_value" display="lv_obj_set_subject_increment_event_max_value()" /> and
  <ApiLink name="lv_obj_set_subject_increment_event_rollover" display="lv_obj_set_subject_increment_event_rollover()" />.
* <ApiLink name="lv_obj_add_subject_set_int_event" display="lv_obj_add_subject_set_int_event()" />,
  <ApiLink name="lv_obj_add_subject_set_float_event" display="lv_obj_add_subject_set_float_event()" /> (requires <ApiLink name="LV_USE_FLOAT" />)
  and <ApiLink name="lv_obj_add_subject_set_string_event" display="lv_obj_add_subject_set_string_event()" />
  write a fixed value on the trigger.

<Callout type="warning">
  Do not delete a Subject while these events remain attached as their callbacks saved a pointer to the Subject.
</Callout>
