Description
I’m in the classic situation where i set a callback function to a button with:
lv_obj_set_event_cb(btn_tmp, ssid_selected);
and the function:
void ssid_selected(lv_obj_t * obj, lv_event_t event){
/* My code */
}
But now i whant to insert an extra argument to the function, such as:
lv_obj_set_event_cb(btn_tmp, ssid_selected(string));
and
void ssid_selected(lv_obj_t * obj, lv_event_t event, char *string){
/* My code */
}
How can i do this?
What MCU/Processor/Board and compiler are you using?
ESP32 on Arduino Toolchain.
What do you want to achieve?
An action function with an extra argument to my button.
What have you tried so far?
The code above mentioned.
Hi,
See:
uint8_t protect; /**< Automatically happening actions can be prevented. 'OR'ed values from
`lv_protect_t`*/
lv_opa_t opa_scale; /**< Scale down the opacity by this factor. Effects all children as well*/
lv_coord_t ext_draw_pad; /**< EXTtend the size in every direction for drawing. */
#if LV_USE_OBJ_REALIGN
lv_reailgn_t realign; /**< Information about the last call to ::lv_obj_align. */
#endif
#if LV_USE_USER_DATA
lv_obj_user_data_t user_data; /**< Custom user data for object. */
#endif
} lv_obj_t;
/*Protect some attributes (max. 8 bit)*/
enum {
LV_PROTECT_NONE = 0x00,
LV_PROTECT_CHILD_CHG = 0x01, /**< Disable the child change signal. Used by the library*/
LV_PROTECT_PARENT = 0x02, /**< Prevent automatic parent change (e.g. in lv_page)*/
and:
void * lv_obj_get_ext_attr(const lv_obj_t * obj);
/**
* Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.
* E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj"
* @param obj pointer to an object which type should be get
* @param buf pointer to an `lv_obj_type_t` buffer to store the types
*/
void lv_obj_get_type(const lv_obj_t * obj, lv_obj_type_t * buf);
#if LV_USE_USER_DATA
/**
* Get the object's user data
* @param obj pointer to an object
* @return user data
*/
lv_obj_user_data_t lv_obj_get_user_data(const lv_obj_t * obj);
/**
* Get a pointer to the object's user data
* @param obj pointer to an object
1 Like
Thanks, i will give a try.
Ok, i’m using lv_obj_set_user_data
and lv_obj_get_user_data
. But now the problem is that the object is a local variable, so i can’t call it in the callback function. I show you why.
I need to create a button list of available wifi networks around me, so i used the following commands:
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay_ms(10);
int n = WiFi.scanNetworks();
if (n == 0) {
} else{
String ssid[n];
String rssi[n];
for (int i = 0; i < n; ++i) {
ssid[i] = WiFi.SSID(i);
rssi[i] = WiFi.RSSI(i);
delay_ms(10);
}
wifi_lst = lv_list_create(lv_scr_act(), NULL);
lv_obj_set_size(wifi_lst, 300, 180);
lv_obj_align(wifi_lst, NULL, LV_ALIGN_CENTER, 0, 0);
uint8_t ssid_buf_len = 80;
uint8_t str_buf_len = 100;
for(int i = 0; i<n; i++) {
char ssid_char[ssid_buf_len];
char str_char[str_buf_len];
(ssid[i] + " (" + rssi[i] + " dB)").toCharArray(str_char, str_buf_len);
lv_obj_t *btn_tmp = lv_list_add_btn(wifi_lst, LV_SYMBOL_WIFI, str_char);
lv_obj_set_user_data(btn_tmp,ssid_char);
lv_obj_set_event_cb(btn_tmp, ssid_selected);
}
}
But, obviously, the callback function can’t call the object btn_tmp. How can i do this?
The object that’s passed to the event callback is btn_tmp
.
You are right. But how can i use lv_obj_get_user_data
? I’m trying something like:
void ssid_selected(lv_obj_t *obj, lv_event_t event){
if(event == LV_EVENT_SHORT_CLICKED){
Serial.println((char*)lv_obj_get_user_data(obj));
lv_btn_set_state(wifi_btn, LV_BTN_STATE_TGL_REL);
lv_obj_del(wifi_lst);
wifi_icon_update();
}
}
But it returns nosense strings.
ssid_char
is a local variable, so it loses its value outside of that for
loop. You’ll need to allocate a buffer to store that string in and then call lv_obj_set_user_data
with the pointer to that buffer.
Perfect, it works! Thank you,
Alberto.
One moment. I noticed it return always the last button! How can i solve it?
I wonder what is the sense of using lv_obj_get_user_data with a global variable, if i can take that variable directly.
If you have a global variable, you can use that variable directly. In this case, the value of ssid_char
is specific to each button, so you would want to use user_data for that.
What returns the last button? lv_list_add_btn
returns a pointer to whatever button it created.
I mean the following.
I have three networks around me. When i create the list with
for(int i = 0; i<n; i++) {
(ssid[i] + " (" + rssi[i] + " dB)").toCharArray(str_char, str_buf_len);
ssid[i].toCharArray(ssid_char,ssid_buf_len);
lv_obj_t *btn_tmp = lv_list_add_btn(wifi_lst, LV_SYMBOL_WIFI, str_char);
lv_obj_set_user_data(btn_tmp,ssid_char);
lv_obj_set_event_cb(btn_tmp, ssid_selected);
}
I can see all three networks ordered by signal quality (we call them WiFi1, WiFi2 and WiFi3).
I used global variables, as you suggested:
// Variables for wifi networks list
const uint8_t ssid_buf_len = 80;
const uint8_t str_buf_len = 100;
char ssid_char[ssid_buf_len];
char str_char[str_buf_len];
My callback function is
void ssid_selected(lv_obj_t *obj, lv_event_t event){
upper_bar_update();
if(event == LV_EVENT_SHORT_CLICKED){
Serial.println((char*)lv_obj_get_user_data(obj));
lv_btn_set_state(wifi_btn, LV_BTN_STATE_TGL_REL);
lv_obj_del(wifi_lst);
}
}
But whichever connection I choose it prints always the last one.
I didn’t suggest using a global variable. I suggested allocating a buffer (e.g. using malloc
or lv_mem_alloc
) for each string. When you use a global variable it will also get overriden each time the for
loop runs.
I never used it. How can i implement malloc
in my code? When can i use free
to deallocate memory?
You can free the memory when the button is deleted (LV_EVENT_DELETE
should work for this purpose).
if(event == LV_EVENT_DELETE){
free(lv_obj_get_user_data(obj));
}