Search objects by name

What i am currently missing is a function to assign an id/name to an object and search for objects. The current object id (LV_USE_OBJ_ID) can not be set directly. Something like document.getElementById(…).

I can implement this feature if desired and if we can agree on an API.

1 Like

It would be very useful indeed. I think the API could be something like

lv_display_get_obj_by_id(display, "id"); //If display==NULL use the default display

Where display is like document and obj is like Element. What do you think?

1 Like

I think that would work like most people would expect that feature to work.

The other question is how to set the id, i think there are multiple possible ways:

  • Combine it with the existing OBJ_ID feature and create a new method:
    lv_obj_set_id(obj, "id")
    This call would replace the id from lv_obj_assign_id with the new id. This might be the easiest way to implement the feature but feels hacky to me, because obj->id is of type void*.

  • Create new fields next to obj->id and global->objid_array/objid_count and add a method to set the name (id is used by OBJ_ID):
    lv_obj_set_name(obj, "name")
    The method should verify that names are unique.
    It is possible to handle the names without adding a field to the object and store all required informations in global (name and pointer to object pairs).

You may propose a method to set object ID directly to document.getElementById() for easier access and manipulation of LVGL objects.

1 Like

I think shouldn’t be required to use unique names. Imagine that you have a complex slider component with

  1. a container
  2. a slider
  3. +/- buttons
  4. a label for the value

It would be nice to call the widgets “slider”, “btn+”, “btn-”, “label” and use a unique name only for the container., e.g. “my_slider1”.

This way we can do this:

lv_obj_t * slider_comp = my_slider_create(parent, "my_slider1");
lv_obj_t * label = lv_obj_get_child_from_id(slider_comp, "label");

slider_comp = my_slider_create(parent, "my_slider7");
label = lv_obj_get_child_from_id(slider_comp, "label");

lv_obj_get_child_from_id could be an other function besides lv_display_get_obj_by_id.

What do you think?

That makes sense, so

lv_obj_get_child_from_id / lv_display_get_obj_by_id

returns only the first matching object.

Yes, just return the first match.

Just a minor correction to unify the API:

lv_obj_get_child_by_id        //"by" instead of "for"
lv_display_get_obj_by_id

Ok, to sum things up. There are 3 methods required to implement this:

lv_obj_get_child_by_id/  lv_obj_get_child_by_name
lv_display_get_obj_by_id / lv_display_get_obj_by_name
lv_obj_set_id / lv_obj_set_name // calling with NULL as id would delete the id

I’m not sure if the term id should be used here, because there is already another feature called obj_id.

I would suggest to create an array or list of lv_obj_t*/char* pairs in lv_global_t and add an entry for each object that the user defined an id for. This implemantation would store anything in the global struct.

Pro:

  • no need the change lv_obj_t struct
    Con:
  • on every obj delete the entire list of pairs must be searched if there is an entry for the object

To avoid the search on every delete, a bool has_id could be added to lv_obj_t.

I think we can store the name or id in the widget itself, but please open a GitHub issue. I think some people would like to comment on this feature. :slight_smile:

I opened a new github issue for this topic.

1 Like

This is what I used to use in my ui applications:
The idea is that there should exist a function called lv_obj_get_name() that returns the name of the object passed as param, this way we can define the function find_child that search for a child of the obj passed as first arg having the name passa as second arg.

here the sample code

 lv_obj *find_child(GtkWidget *parent, const gchar *name)
 {
     static int tabs = 0;
     if(parent!=NULL){

         if (parent && g_ascii_strcasecmp(lv_obj_get_name(parent), (gchar *)name) == 0) {
             return parent;
         }

         if (LV_IS_BIN(parent)) {
             if(lv_bin_get_child(LV_BIN(parent))){
                 tabs+=4;
                 return find_child(lv_bin_get_child(LV_BIN(parent)), name);
                 tabs-=4;
             }
         }

         if (LV_IS_CONTAINER(parent)) {
             GList *children = lv_container_get_children(LV_CONTAINER(parent));
             do {
                 if(children && children->data){
                     tabs+=4;
                     lv_obj *widget = find_child(children->data, name);
                     if (widget != NULL) {
                         return widget;
                     }
                     tabs-=4;
                 }
             } while ((children = g_list_next(children)) != NULL);
         }

     }

     return NULL;
 }

What is LV_IS_BIN?

Hi Gabor, this is just a pseudo code derived from my previous work, a bin is a widget containing one child, a container is a widget containing more children.

Feel free to modify it

1 Like