docs/src/common-widget-features/tree.rst
.. _obj_tree:
Parents and Children
LVGL stores Widgets in a parent-child structure (tree). The root element is the Screen, which has no parent.
When a Widget is created, a pointer to its parent is passed to the create function.
LVGL provides many useful functions to modify the Widget tree and get information about it:
:cpp:expr:lv_obj_get_screen(widget): Get a Widget's screen ("root" parent).
:cpp:expr:lv_obj_get_parent(widget): Get the Widget's current parent.
lv_obj_set_parent(widget, new_parent): Move the Widget to a new parent.
The Widget will become the top-most (last/youngest) child of the new parent.
:cpp:expr:lv_obj_get_child(parent, idx): Return a specific child of a parent.
Some examples for idx:
0: get the first created child1: get the second created child-1: get the last created child:cpp:expr:lv_obj_get_child_by_type(parent, idx, &lv_slider_class): Similar to :cpp:expr:lv_obj_get_child but filters to children
with a given type.
:cpp:expr:lv_obj_find_by_name(parent, "text"): Find a Widget with a given name under a parent. It does not have to be a direct child.
:cpp:expr:lv_obj_get_child_by_name(parent, "container/button/text"): Get a Widget by navigating a path using parent names (separated by /).
:cpp:expr:lv_obj_get_index(widget): Return the index of the Widget in its parent.
It is equivalent to the number of older siblings in the parent.
:cpp:expr:lv_obj_move_to_index(widget, idx): Move the Widget to a specified index.
0 is the oldest child's position, -1 is the youngest.
:cpp:expr:lv_obj_swap(widget1, widget2): Swap the positions of two Widgets.
To iterate through a parent widget's children:
.. code-block:: c
uint32_t i;
uint32_t count = lv_obj_get_child_count(parent);
for(i = 0; i < count; i++) {
lv_obj_t * child = lv_obj_get_child(parent, i);
/* Do something with `child`. */
}
.. _widget_names:
Names
When a Widget is created, its reference can be stored in an :cpp:expr:lv_obj_t * pointer
variable. To use this Widget in multiple places in the code, the variable can be passed
as a function parameter or made global. However, this approach has some drawbacks:
.. _tree_setting_names:
To address these issues, LVGL introduces a powerful Widget naming system that can be enabled
by setting :c:macro:LV_USE_OBJ_NAME in lv_conf.h.
A custom name can be assigned using :cpp:expr:lv_obj_set_name(obj, "name") or
:cpp:expr:lv_obj_set_name_static(obj, "name"). The "static" variant requires that the passed
name remains valid while the Widget exists, since only the pointer is stored. Otherwise, LVGL will
allocate memory to store a copy of the name.
If a name ends with #, LVGL will automatically replace it with an index based on the
number of siblings with the same base name. If no name is provided, the default is
<widget_type>_#.
Below is an example showing how manually and automatically assigned names are resolved:
Main lv_obj container named "cont": "cont"
lv_obj container named "header": "header"
lv_label with no name: "lv_label_0"lv_label named "title": "title"lv_label with no name: "lv_label_1" (It's the third label, but custom-named Widgets are not counted)lv_obj container named "buttons":
lv_button with no name: "lv_button_0"lv_button named "second_button": "second_button"lv_button with no name: "lv_button_1"lv_button named lv_button_#: "lv_button_2"lv_button named mybtn_#: "mybtn_0"lv_button with no name: "lv_button_2"lv_button named mybtn_#: "mybtn_1"lv_button named mybtn_#: "mybtn_2"lv_button named mybtn_#: "mybtn_3"Note that these indices are "fluid", meaning if "mybtn_2" above is deleted, the button previously known as "mybtn_3" will thereafter be known as "mybtn_2", since the indices are resolved when names are being found by name, not when they are set. Keep this in mind when Finding Widgets as described below.
Widgets can be found by name in two ways:
Get a direct child by name using :cpp:expr:lv_obj_get_child_by_name(parent, "child_name").
Example:
:cpp:expr:lv_obj_get_child_by_name(header, "title").
You can also use a path to find nested children:
:cpp:expr:lv_obj_get_child_by_name(cont, "buttons/mybtn_2").
Find a descendant at any level using :cpp:expr:lv_obj_find_by_name(parent, "child_name").
Example:
:cpp:expr:lv_obj_find_by_name(cont, "mybtn_1")
Note that "mybtn_1" is a child of cont at any level, not necessarily a
direct child. This is useful when you want to ignore the hierarchy and search by
name alone.
Since both functions start searching from a specific parent, it's possible to have multiple Widget subtrees with identical names under different parents.
For example, if my_listitem_create(parent) creates a Widget named "list_item_#"
with direct children "icon", "title", "ok_button", and "lv_label_0",
and it is called 10 times, a specific "ok_button" can be found like this:
.. code-block:: c
lv_obj_t * item = lv_obj_find_by_name(lv_screen_active(), "list_item_5");
lv_obj_t * ok_btn = lv_obj_find_by_name(item, "ok_button");
// Or
lv_obj_t * ok_btn = lv_obj_get_child_by_name(some_list_container, "list_item_5/ok_button");