# Widget Tree (/common-widget-features/tree)



Parents and Children [#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:

* <ApiLink name="lv_obj_get_screen" display="lv_obj_get_screen(widget)" />: Get a Widget's screen ("root" parent).
* <ApiLink name="lv_obj_get_parent" display="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.
* <ApiLink name="lv_obj_get_child" display="lv_obj_get_child(parent, idx)" />: Return a specific child of a parent.
  Some examples for `idx`:

  * `0`: get the first created child
  * `1`: get the second created child
  * `-1`: get the last created child
* <ApiLink name="lv_obj_get_child_by_type" display="lv_obj_get_child_by_type(parent, idx, &lv_slider_class)" />: Similar to <ApiLink name="lv_obj_get_child" /> but filters to children
  with a given type.
* <ApiLink name="lv_obj_find_by_name" display="lv_obj_find_by_name(parent, &#x22;text&#x22;)" />: Find a Widget with a given name under a parent. It does not have to be a direct child.
* <ApiLink name="lv_obj_get_child_by_name" display="lv_obj_get_child_by_name(parent, &#x22;container/button/text&#x22;)" />: Get a Widget by navigating a path using parent names (separated by `/`).
* <ApiLink name="lv_obj_get_index" display="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.
* <ApiLink name="lv_obj_move_to_index" display="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.
* <ApiLink name="lv_obj_swap" display="lv_obj_swap(widget1, widget2)" />: Swap the positions of two Widgets.

To iterate through a parent widget's children:

```c title=" " lineNumbers=1
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`. */
}
```

Names [#names]

When a Widget is created, its reference can be stored in an <ApiLink name="lv_obj_t" display="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:

* Using global variables adds names to the global namespace and is thus generally not recommended.
* It's not scalable. Passing references to 20 Widgets as function parameters is not ideal.
* Tracking whether a Widget still exists or has been deleted requires extra logic and can be tricky.

Setting Names [#setting-names]

To address these issues, LVGL introduces a powerful Widget naming system that can be enabled
by setting <ApiLink name="LV_USE_OBJ_NAME" /> in `lv_conf.h`.

A custom name can be assigned using <ApiLink name="lv_obj_set_name" display="lv_obj_set_name(obj, &#x22;name&#x22;)" /> or
<ApiLink name="lv_obj_set_name_static" display="lv_obj_set_name_static(obj, &#x22;name&#x22;)" />. 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.

Finding Widgets [#finding-widgets]

Widgets can be found by name in two ways:

1. **Get a direct child by name** using <ApiLink name="lv_obj_get_child_by_name" display="lv_obj_get_child_by_name(parent, &#x22;child_name&#x22;)" />.
   Example:
   <ApiLink name="lv_obj_get_child_by_name" display="lv_obj_get_child_by_name(header, &#x22;title&#x22;)" />.
   You can also use a path to find nested children:
   <ApiLink name="lv_obj_get_child_by_name" display="lv_obj_get_child_by_name(cont, &#x22;buttons/mybtn_2&#x22;)" />.
2. **Find a descendant at any level** using <ApiLink name="lv_obj_find_by_name" display="lv_obj_find_by_name(parent, &#x22;child_name&#x22;)" />.
   Example:
   <ApiLink name="lv_obj_find_by_name" display="lv_obj_find_by_name(cont, &#x22;mybtn_1&#x22;)" />
   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:

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