Components

Overview

<component> the following child elements:

  • <consts>,

  • <api>,

  • <styles>, and

  • <view>.

Unlike Widgets (which are always compiled into the application), Components can either:

  1. be loaded at runtime from XML, or

  2. be exported to C code and compiled with the application.

Usage from Exported Code

From each Component XML file, a C and H file is exported with a single function inside:

lv_obj_t * component_name_create(lv_obj_t * parent, ...api properties...);

where 'component_name' (in the function above) is replaced by the Component's XML file name.

When a Component is used in another Component's XML code and the code is exported, this create function will be called. This means that Components do not have a detailed set/get API but can be created with a fixed set of parameters.

If the user needs to access or modify values dynamically, it is recommended to use a Subject.

The user can also call these ..._create() functions at any time from application code.

Usage from XML

Registration

Once a Component is created (e.g., my_button), it can be registered by calling either:

  • lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml");

  • lv_xml_component_register_from_data("my_button", xml_data_of_my_button);

These registration functions process the XML data and store relevant information internally. This is required to make LVGL recognize the Component by name.

Note that the "A:" in the above path is a file system "driver identifier letter" from File System (lv_fs_drv) and used accordingly. See that documentation for details.

When loaded from a file, the file name is used as the Component name.

Instantiation

After registration, a new instance of any registered Component can be created with:

lv_obj_t * obj = lv_xml_create(lv_screen_active(), "my_button", NULL);

The created Widget is a normal LVGL Widget that can be used like any other manually-created Widget.

The last parameter can be NULL or an attribute list, like this:

/* Can be local */
char * my_button_attrs[] = {
    "x", "10",
    "y", "-10",
    "align", "bottom_left",
    "btn_text", "New button",
    NULL, NULL,
};

lv_obj_t * btn1 = lv_xml_create(lv_screen_active(), "my_button", my_button_attrs);

Parameters

The properties of child elements can be adjusted, such as:

<lv_label x="10" text="Hello"/>

These parameters can be set to a fixed value. However, with the help of <prop> elements inside the <api> tag, they can also be passed when an instance is created. Only the whole property can be passed, but not individual <param> elements.

Additionally, when a Component is created, it can use the extended Widget's attributes (see <view extends="..."> in the code examples below).

This means that Components inherit the API of the extended Widget as well.

The following example demonstrates parameter passing and the use of the text label property on a Component:

<!-- h3.xml -->
<component>
    <view extends="lv_label"/>
</component>
<!-- red_button.xml -->
<component>
    <api>
        <prop type="string" name="btn_text" default="None"/>
    </api>
    <view extends="lv_button" style_radius="0" style_bg_color="0xff0000">
        <h3 text="Some text"/>
        <h3 text="$btn_text" y="40"/>
    </view>
</component>
lv_xml_component_register_from_file("A:path/to/h3.xml");
lv_xml_component_register_from_file("A:path/to/red_button.xml");

/* Creates a button with "None" text */
lv_xml_create(lv_screen_active(), "red_button", NULL);

/* Use attributes to set the button text */
const char * attrs[] = {
    "btn_text", "Click here",
    NULL, NULL,
};
lv_xml_create(lv_screen_active(), "red_button", attrs);

Example

Load components at runtime

#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_XML

void lv_example_xml_1(void)
{
    /*A red button created from builti-in LVGL widgets
     *It has an API parameter too to change its text.*/
    const char * red_button_xml =
        "<component>"
        "  <api>"
        "    <prop name=\"button_text\" type=\"string\" default=\"None\"/>"
        "  </api>"
        "  <view extends=\"lv_button\" radius=\"0\" style_bg_color=\"0xa91500\">"
        "    <lv_label text=\"$button_text\" align=\"center\"/>"
        "  </view>"
        "</component>";

    /*The card is just an lv_obj where a label and two red buttons are used.
     * Its API allow setting a title (label test) and the action (the text of a button)*/
    const char * card_xml =
        "<component>"
        "  <api>"
        "    <prop name=\"title\" type=\"string\" default=\"Hello world\"/>"
        "    <prop name=\"action\" type=\"string\"/>"
        "  </api>"
        "  <view width=\"200\" height=\"content\">"
        "    <lv_label text=\"$title\" align=\"top_mid\"/>"
        "    <red_button y=\"20\" align=\"top_left\" button_text=\"Cancel\"/>"
        "    <red_button y=\"20\" align=\"top_right\" button_text=\"$action\"/>"
        "  </view>"
        "</component>";

    /* Motor card is a special case of a card where the title and action are already set*/
    const char * motor_card_xml =
        "<component>"
        "  <view extends=\"card\" title=\"Motor start?\" action=\"Start\">"
        "  </view>"
        "</component>";

    /*Register all the custom components*/
    lv_xml_component_register_from_data("red_button", red_button_xml);
    lv_xml_component_register_from_data("card", card_xml);
    lv_xml_component_register_from_data("motor_card", motor_card_xml);

    lv_obj_t * card;
    /*Create a card with the default values*/
    card = (lv_obj_t *) lv_xml_create(lv_screen_active(), "card", NULL);

    /*Create a motor card too. The returned value can be adjusted freely*/
    card = (lv_obj_t *) lv_xml_create(lv_screen_active(), "motor_card", NULL);
    lv_obj_set_y(card, 90);

    /*Pass properties to a card*/
    const char * attrs[] = {
        "y", "180",
        "action", "Apply",
        "title", "New title",
        NULL, NULL,
    };
    card = (lv_obj_t *) lv_xml_create(lv_screen_active(), "card", attrs);

}
#endif

#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_XML

void lv_example_xml_2(void)
{
    lv_result_t res;
    res = lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_h3.xml");
    if(res != LV_RESULT_OK) {
        lv_obj_t * label = lv_label_create(lv_screen_active());
        lv_label_set_text(label, "Couldn't open the XML files.");
        lv_obj_center(label);
        return;
    }
    lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_card.xml");
    lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml");
    lv_xml_component_register_from_file("A:lvgl/examples/others/xml/view.xml");

    lv_xml_register_font(NULL, "lv_montserrat_18", &lv_font_montserrat_18);

    lv_obj_t * obj = (lv_obj_t *) lv_xml_create(lv_screen_active(), "view", NULL);
    lv_obj_set_pos(obj, 10, 10);

    const char * my_button_attrs[] = {
        "x", "10",
        "y", "-10",
        "align", "bottom_left",
        "btn_text", "New button",
        NULL, NULL,
    };

    lv_xml_component_unregister("my_button");

    lv_xml_create(lv_screen_active(), "my_button", my_button_attrs);

    const char * slider_attrs[] = {
        "x", "200",
        "y", "-15",
        "align", "bottom_left",
        "value", "30",
        NULL, NULL,
    };

    lv_obj_t * slider = (lv_obj_t *) lv_xml_create(lv_screen_active(), "lv_slider", slider_attrs);
    lv_obj_set_width(slider, 100);
}
#endif

API