Learn the Basics

Learn how to use LVGL in a few minutes

Edit on GitHub

In LVGL you dynamically create and delete screens and widgets to build up your UI. Styles, animations, event handlers, and data bindings can also be added to make the UI look better and connect it easily to an application.

Display

A Display refers to the actual hardware. In order to connect LVGL to the hardware an lv_display_t object needs to be created and initialized.

See the Quick porting guide.

Screen

Screens are LVGL widgets created on a Display. They are logical containers for other widgets. A display can have multiple screens, but there is always a single active screen, which can be retrieved by using lv_screen_active. It returns an lv_obj_t * pointer. See Active Screen for more information.

The most common way to create a screen is by creating a Base widget with a NULL parent. E.g.

 
lv_obj_t * my_screen = lv_obj_create(NULL);

A screen can be loaded like this: lv_screen_load(my_screen)

Widgets

Widgets are the basic building blocks of the UI. For example: Button (lv_button), Slider (lv_slider), Drop-Down List (lv_dropdown), Chart (lv_chart), etc.

Widgets can be created dynamically by calling their respective create functions. The create function returns an lv_obj_t * pointer which can be used to configure the widget later.

Each create function has a single parent argument that defines which widget the new one will be added to.

For example:

 
lv_obj_t * my_button1 = lv_button_create(lv_screen_active());
lv_obj_t * my_label1 = lv_label_create(my_button1);

If a widget or screen is no longer needed, it can be removed by calling

lv_obj_delete(my_button1)

To change the properties of widgets, two sets of functions can be used:

Here is an example that also shows some non-pixel units for sizes:

 
lv_obj_t * my_button1 = lv_button_create(lv_screen_active());
/* Set parent-sized width, and content-sized height */
lv_obj_set_size(my_button1, lv_pct(100), LV_SIZE_CONTENT);
/* Align to the right center with 20px offset horizontally */
lv_obj_align(my_button1, LV_ALIGN_RIGHT_MID, -20, 0);

lv_obj_t * my_label1 = lv_label_create(my_button1);
lv_label_set_text(my_label1, "Click me!");
/* Make the text red */
lv_obj_set_style_text_color(my_label1, lv_color_hex(0xff0000), 0);

To see the full API for any widget, see its documentation at All Widgets, or check its related header file in the source code.

Events

Events are used to inform the application that something has happened with a Widget. You can assign one or more callbacks to a Widget which will be called when the Widget is clicked, released, dragged, being deleted, etc.

A callback is assigned like this:

 
lv_obj_add_event_cb(btn, my_btn_event_cb, LV_EVENT_CLICKED, NULL);

...

void my_btn_event_cb(lv_event_t * e)
{
    printf("Clicked\n");
}

LV_EVENT_ALL can be used instead of LV_EVENT_CLICKED to invoke the callback for all events.

Event callbacks receive the argument lv_event_t * e containing the current event code and other event-related information. The current event code can be retrieved with:

 
lv_event_code_t code = lv_event_get_code(e);

The Widget that triggered the event can be retrieved with:

 
lv_obj_t * widget = lv_event_get_target_obj(e);

Learn all about Events in the events section.

Parts and States

Parts

Widgets are built from one or more parts. For example, a button has only one part called LV_PART_MAIN. However, a Slider (lv_slider) has LV_PART_MAIN, LV_PART_INDICATOR and LV_PART_KNOB.

By using parts you can apply different styles to the different parts of a widget.

Read the specific Widget's documentation to learn which parts it uses.

States

Widgets can be in a combination of the following states:

For example, if you press a Widget it will automatically go to the LV_STATE_FOCUSED and LV_STATE_PRESSED states. When you release it, the LV_STATE_PRESSED state will be removed while the LV_STATE_FOCUSED state remains active.

To check if a Widget is in a given state use lv_obj_has_state(widget, LV_STATE_...). It will return true if the Widget is currently in that state.

To programmatically add or remove states use:

 
lv_obj_add_state(widget, LV_STATE_...);
lv_obj_remove_state(widget, LV_STATE_...);

Styles

Initializing styles

Styles are carried in lv_style_t objects. They contain properties such as background color, border width, font, etc.

The styles can be added to a widget's given Part and State. Only their pointer is saved in the Widgets so they need to be defined as static or global variables.

Before using a style it needs to be initialized with lv_style_init(&style1). After that, properties can be added to configure the style. For example:

 
static lv_style_t style1;
lv_style_init(&style1);
lv_style_set_bg_color(&style1, lv_color_hex(0xa03080));
lv_style_set_border_width(&style1, 2);

See Styles Overview for more details.

See Style Properties to see the full list.

Adding styles to the widgets

After that it can be added to widgets:

 
lv_obj_add_style(my_button1, &style1, 0); /*0 means add to the main part and default state*/
lv_obj_add_style(my_checkbox1, &style1, LV_STATE_DISABLED); /*Add to checkbox's disabled state*/
lv_obj_add_style(my_slider1, &style1, LV_PART_KNOB | LV_STATE_PRESSED); /*Add to the slider's knob pressed state*/

Inheritance

Some properties (particularly the text-related ones) can be inherited. This means if a property is not set in a Widget it will be searched for in its parents. For example, you can set the font once in the screen's style and all text on that screen will inherit it by default, unless the font is specified on the widget or one of its parents.

Local styles

Local style properties can also be added to Widgets. The local style properties affect only the targeted widget.

 
lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED);

See Styles for full details.

Data bindings

To realize data bindings, LVGL uses the Subject/Observer pattern.

Subjects are lv_subject_t objects that store integer, color, string, etc. values. They are created with lv_subject_create and freed with lv_subject_delete.

Either the UI or the application can subscribe to these subjects by creating observer callbacks that are notified when the subject changes.

A widget can also subscribe to a subject. This way, when the widget is deleted, it will be automatically unsubscribed.

For some widgets, helper functions make it simple to connect them to subjects. E.g.: lv_slider_bind_value, lv_label_bind_text.

In general, using subjects and observers is a way to connect various parts of the UI and make them dynamically react to application data changes, or allow the application to react to UI changes.

 
static void label_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
{
    lv_obj_t * label = lv_observer_get_target_obj(observer);
    lv_label_set_text_fmt(label, "Progress: %d", lv_subject_get_int(subject));
}

...

static lv_subject_t * subject1;
subject1 = lv_subject_create(LV_SUBJECT_TYPE_INT);
lv_subject_set_int(subject1, 10);

lv_obj_t * label1 = lv_label_create(lv_screen_active());
/*lv_label_bind_text could have been used too*/
lv_subject_add_observer_obj(subject1, label_observer_cb, label1, NULL);

lv_obj_t * slider1 = lv_slider_create(lv_screen_active());
lv_slider_bind_value(slider1, subject1);
lv_obj_set_y(slider1, 30);

lv_subject_set_int(subject1, 30);

Learn more on the documentation page of Observers.

Last updated on

On this page