diff --git a/docs/src/details/common-widget-features/tree.rst b/docs/src/details/common-widget-features/tree.rst index 3c865bafbf..e6329690be 100644 --- a/docs/src/details/common-widget-features/tree.rst +++ b/docs/src/details/common-widget-features/tree.rst @@ -7,17 +7,17 @@ Widget Tree Parents and Children ******************** -LVGL stores widgets in a parent-child structure (tree). -The root element is the screen, which has no parent. +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. +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: +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_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``: @@ -26,13 +26,13 @@ LVGL provides many useful functions to modify the widget tree and get informatio - ``-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. +- :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. +- :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. +- :cpp:expr:`lv_obj_swap(widget1, widget2)`: Swap the positions of two Widgets. To iterate through a parent widget's children: @@ -52,23 +52,26 @@ To iterate through a parent widget's children: 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 +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: - 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. +- 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. + + +.. _tree_setting_names: Setting Names ------------- -To address these issues, LVGL introduces a powerful widget naming system that can be enabled +To address these issues, LVGL introduces a powerful Widget naming system that can be enabled by setting ``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 +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 @@ -83,7 +86,7 @@ Below is an example showing how manually and automatically assigned names are re - ``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_label`` with no name: "lv_label_1" (It's the third label, but custom-named Widgets are not counted) - ``lv_obj`` container named ``"buttons"``: @@ -97,6 +100,12 @@ Below is an example showing how manually and automatically assigned names are re - ``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 --------------- @@ -104,4 +113,28 @@ Widgets can be found by name in two ways: 1. **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")` + :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")`. + +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");