How can I style each of the children in the msgbox?

Description

How can I style each of the children in the msgbox?

What MCU/Processor/Board and compiler are you using?

STM32F767IIT

What LVGL version are you using?

7.10.1

What do you want to achieve?

  1. Can the size or color of the symbol be different from the text?
  2. Can the font or color of the first line be different from other lines?
  3. Can I specify a different size or color for the button?

What have you tried so far?

Code to reproduce

Add a code snippet which can run in the simulator. It should contain only the relevant code that compiles without errors when separated from your main code base.

The code block(s) should be formatted like:

		static lv_style_t style_msgbox;
		lv_style_init(&style_msgbox);
		lv_style_set_text_font(&style_msgbox, LV_STATE_DEFAULT, &lv_font_montserrat_20);
		lv_style_set_text_color(&style_msgbox, LV_STATE_DEFAULT, LV_COLOR_BLACK);
		lv_style_set_bg_color(&style_msgbox, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
		lv_style_set_
		//lv_style_set_size(style, state, value)


		static const char * btns[] = {"Close", ""};
		lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
		lv_obj_set_event_cb(mbox1, event_handler);
		lv_msgbox_set_text(mbox1, LV_SYMBOL_WARNING " Setting value input error\n"
									                "There is no value. Please enter a value." );
		lv_msgbox_add_btns(mbox1, btns);
		lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0);

		lv_obj_add_style(mbox1, LV_MSGBOX_PART_BG, &style_msgbox);

Screenshot and/or video

For 3), the buttons can be styled by adding a style to LV_MSGBOX_PART_BTN (after you call lv_msgbox_add_btns), in a similar fashion to how you styled LV_MSGBOX_PART_BG

For 1) and 2), I don’t think you can mix font sizes within a label, but you can create additional labels on the msgbox (with the msgbox as parent), and break your output text between lv_msgbox_set_text for the first line, and use your labels for other lines.

The symbol (and other text) can be recolored in the msgbox text by accessing the msgbox label and setting its recolor attribute to true (thanks to @embeddedt for the update). This code:

static lv_style_t style_msgbox;
lv_style_init(&style_msgbox);
lv_style_set_text_font(&style_msgbox, LV_STATE_DEFAULT, &lv_font_montserrat_20);
lv_style_set_text_color(&style_msgbox, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_bg_color(&style_msgbox, LV_STATE_DEFAULT, LV_COLOR_YELLOW);

static lv_style_t style_buttons;
lv_style_init(&style_buttons);
lv_style_set_text_font(&style_buttons, LV_STATE_DEFAULT, &lv_font_montserrat_12);
lv_style_set_text_color(&style_buttons, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_bg_color(&style_buttons, LV_STATE_DEFAULT, LV_COLOR_GREEN);

static lv_style_t style_label;
lv_style_init(&style_label);
lv_style_set_text_font(&style_label, LV_STATE_DEFAULT, &lv_font_montserrat_16);
lv_style_set_text_color(&style_label, LV_STATE_DEFAULT, LV_COLOR_BLUE);

static const char * btns[] = {"Close", ""};
lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(mbox1, event_handler);
lv_obj_t * label1 = lv_label_create(mbox1, NULL);

lv_msgbox_add_btns(mbox1, btns);
lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0);

lv_obj_add_style(mbox1, LV_MSGBOX_PART_BG, &style_msgbox);
lv_obj_add_style(label1, LV_LABEL_PART_MAIN, &style_label);
lv_obj_add_style(mbox1, LV_MSGBOX_PART_BTN, &style_buttons);

//Access msgbox label and set it to enable recoloring
lv_obj_t * msgbox_label = ((lv_msgbox_ext_t *)lv_obj_get_ext_attr(mbox1))->text;
if(msgbox_label)
    lv_label_set_recolor(msgbox_label, true);

lv_msgbox_set_text(mbox1, "#ff0000 " LV_SYMBOL_WARNING "# Setting value input error\n");
lv_label_set_text(label1, "There is no value. Please enter a value." );

produced this:
Untitled

If you don’t wish to add additional labels, you can still use the recolor style formatting when calling lv_msgbox_set_text to change the colors of parts of the text.

Correct.

Note that you can actually do this without needing to edit the LVGL sources, since it is possible to access ext_attr data using lv_obj_get_ext_attr. It’s a matter of personal preference - I tend to avoid editing the LVGL files unless I’m planning to PR the change.

lv_obj_t * msgbox_label = ((lv_msgbox_ext_t *)lv_obj_get_ext_attr(msgbox))->text;
if(msgbox_label)
    lv_label_set_recolor(msgbox_label, true);

This kind of hack will often break across major versions, but that doesn’t matter for v7.

In retrospect, it would have made more logical sense to have lv_msgbox_set_recolor enable recoloring on the label as well, but v7 is now feature-frozen, so unfortunately it won’t be possible to add it upstream for that version. We can look into adding this to v8.

1 Like

Fair point, and a “safer” way to do it. I’ll update my example. I was in a hurry when I made the modification for myself, and didn’t consider revisting as I knew I wouldn’t be refreshing v7 source any longer.

1 Like

Thank you for answering in detail. Thanks to this, I was able to decorate the message box in more variety.
But I have one more question. Adjusting the length of the button and moving the position of the label do not work well. Here’s what I’ve done so far.

  1. adjusting the length of the button
 lv_style_set_margin_left(&style_button, LV_STATE_DEFAULT, 100);    // 1st try  
 lv_style_set_size(&style_button, LV_STATE_DEFAULT, LV_DPX(5));   // 2nd try
 lv_style_set_size(&style_button, LV_STATE_DEFAULT, LV_DPX(5));   //  3rd try
 lv_obj_t * mbox1_btn = ((lv_msgbox_ext_t *)lv_obj_get_ext_attr(mbox1))->btnm;   // 4th try
  lv_obj_set_width(mbox1_btn, 100);
  1. moving the position of the label
 lv_obj_align(label1, mbox1, LV_ALIGN_IN_TOP_MID, 0, 10);   // 1st try
 lv_obj_align(label1, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);    // 2nd try

here is full code.

static lv_style_t style_msgbox;
lv_style_init(&style_msgbox);
lv_style_set_text_font(&style_msgbox, LV_STATE_DEFAULT, &lv_font_montserrat_20);
lv_style_set_text_color(&style_msgbox, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_bg_color(&style_msgbox, LV_STATE_DEFAULT, LV_COLOR_YELLOW);

static lv_style_t style_button;
lv_style_init(&style_button);
lv_style_set_bg_opa(&style_button, LV_STATE_DEFAULT, 0);
//		lv_style_set_margin_left(&style_button, LV_STATE_DEFAULT, 100);
//		lv_style_set_size(&style_button, LV_STATE_DEFAULT, LV_DPX(5));

static lv_style_t style_label;
lv_style_init(&style_label);
lv_style_set_text_font(&style_label, LV_STATE_DEFAULT, &lv_font_montserrat_18);
lv_style_set_text_color(&style_label, LV_STATE_DEFAULT, LV_COLOR_BLUE);

static const char * btns[] = {"Close", ""};
lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(mbox1, event_handler);
lv_obj_t * label1 = lv_label_create(mbox1, NULL);
		//lv_obj_align(label1, mbox1, LV_ALIGN_IN_TOP_MID, 0, 10);

lv_msgbox_add_btns(mbox1, btns);
lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0);

lv_obj_add_style(mbox1, LV_MSGBOX_PART_BG, &style_msgbox);
lv_obj_add_style(mbox1, LV_MSGBOX_PART_BTN, &style_button);
lv_obj_add_style(label1, LV_LABEL_PART_MAIN, &style_label);

lv_obj_t * mbox1_label = ((lv_msgbox_ext_t *)lv_obj_get_ext_attr(mbox1))->text;
if(mbox1_label)
	lv_label_set_recolor(mbox1_label, true);

//	      lv_obj_align(mbox1_label, mbox1, LV_ALIGN_IN_TOP_MID, 0, 0);

//		lv_obj_t * mbox1_btn = ((lv_msgbox_ext_t *)lv_obj_get_ext_attr(mbox1))->btnm;
//		lv_obj_set_width(mbox1_btn, 100);

lv_msgbox_set_text(mbox1, "#ff0000 " LV_SYMBOL_WARNING "# #000000 Setting value input error#\n");
lv_label_set_text(label1, "There is no value.\n"
		  		      "Please enter a value.");

Nothing optimal here, and there may be better ways, but a couple of things that would work:

The button matrix button width is ‘automatic’, so you could add a couple of “blank” buttons and hide them:

static const char * btns[] = {"Blank", "Close", "Blank", ""};

and then after calling lv_msgbox_add_btns:

lv_btnmatrix_set_btn_ctrl(lv_msgbox_get_btnmatrix(mbox1), 0, LV_BTNMATRIX_CTRL_HIDDEN);
lv_btnmatrix_set_btn_ctrl(lv_msgbox_get_btnmatrix(mbox1), 2, LV_BTNMATRIX_CTRL_HIDDEN);

Or, don’t add the btn_matrix via lv_msgbox_add_btns at all, and instead create and style your own button on the msgbox, adding it after the label:

lv_obj_t * btn1 = lv_btn_create(mbox1, NULL);
lv_obj_t * btnlabel = lv_label_create(btn1, NULL);
lv_label_set_text(btnlabel, "Close");
lv_obj_set_width(btn1, 80);
lv_obj_add_style(btn1, LV_BTN_PART_MAIN, &style_button);

This works, but it’s getting very unmsgboxy :slight_smile:

For the spacing of your label, try looking at the sources for the message box and experiment with the padding of various elements, unless someone else can chime in with a better solution.


You can check this topic, because MsgBox is automatic layout, so some properties directly set is invalid, after the automatic layout is canceled, although you can set the element properties freely, but the response and update speed of the whole MsgBox will be slow, if your LCD refresh rate is slow, please use with caution.

Thank you. :slightly_smiling_face:
I’ll try it.