LVGL 시뮬레이터에서 내가 만든 UI 코드 실행하기

LVGL PC 시뮬레이터가 제공하는 기본 화면(lv_demo_widgets())은 기능은 충분하지만, 실제 프로젝트를 빠르게 익히기엔 기본 설정이 과하게 느껴질 수 있다. 그래서 src/main.c 안에서 데모를 주석 처리하고, 내가 만든 위젯을 직접 추가하여 LVGL을 학습하기 쉽게 하였다.

1. Custom widget을 추가한 이유?

기존 데모는 처음 LVGL을 배우는 사람에게 좀 과하고, 분석하고 테스트해보기 쉽지는 않아보인다. 기본 샘플을 미리 테스트해보기 위해 기존 UI를 비활성화하고, 기본 코드를 렌더링하는 커스텀 위젯을 추가하였다.

2. 커스텀 위젯 추가 방법

src/main.c에 아래와 같이 create_custom_ui() 함수를 추가한다. 그리고 기존 위젯을 보여주는 코드인 lv_demo_widgets()를 주석 처리한다.

그럼 내가 추가한 위젯이 시뮬레이터에서 보인다.

렌더링해보고 싶은 코드를 커스텀 위젯 함수 안에 넣고, 빌드해서 실행해보면 된다.

3. 기본 샘플 코드 설명

다음 함수는 lv_scr_load로 새 스크린을 만들고, 가운데 정렬된 패널 안에 텍스트, 진행률 표시, 슬라이더, 버튼을 넣는다. 그리고 각 요소에 여백과 너비를 지정한다.

/* src/main.c */
static void create_custom_ui(void)
{
  lv_obj_t *scr = lv_obj_create(NULL);
  lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE);
  lv_scr_load(scr);

  lv_obj_t *panel = lv_obj_create(scr);
  lv_obj_set_size(panel, 360, 240);
  lv_obj_align(panel, LV_ALIGN_CENTER, 0, 0);
  lv_obj_set_style_radius(panel, 18, 0);
  lv_obj_set_style_pad_all(panel, 16, 0);

  lv_obj_t *title = lv_label_create(panel);
  lv_label_set_text(title, "My Custom Widget");
  lv_obj_set_style_text_font(title, &lv_font_montserrat_20, 0);
  lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 0);

  lv_obj_t *status = lv_label_create(panel);
  lv_label_set_text(status, "Default UI ready");
  lv_obj_align_to(status, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 6);

  lv_obj_t *bar = lv_bar_create(panel);
  lv_obj_set_width(bar, 280);
  lv_bar_set_value(bar, 64, LV_ANIM_OFF);
  lv_obj_align_to(bar, status, LV_ALIGN_OUT_BOTTOM_MID, 0, 18);
  lv_obj_set_style_radius(bar, 8, LV_PART_MAIN);
  lv_obj_set_style_pad_row(bar, 12, LV_PART_MAIN);

  lv_obj_t *slider = lv_slider_create(panel);
  lv_slider_set_value(slider, 30, LV_ANIM_OFF);
  lv_obj_set_width(slider, 280);
  lv_obj_align_to(slider, bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 24);

  lv_obj_t *btn = lv_btn_create(panel);
  lv_obj_set_size(btn, 140, 50);
  lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -8);
  lv_obj_t *btn_label = lv_label_create(btn);
  lv_label_set_text(btn_label, "Run Action");
}

main()에서 기존 lv_demo_widgets() 호출을 주석 처리하고 create_custom_ui()를 호출하면, 위 함수가 맨 처음 로딩되는 화면이 된다. 이렇게 직접 만든 패널에 새 위젯을 추가하거나 현재 요소를 수정하며 즉시 결과를 확인하는 흐름이 가능하다.

4. 실행 화면

시뮬레이터 실행

5. 전체 코드 diff

전체 코드 변경 사항은 아래와 같다. 참고하실 분은 참고하세요.

diff --git a/src/main.c b/src/main.c
index c893220..c192c34 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,6 +26,8 @@
 
 #include "hal/hal.h"
 
+static void create_custom_ui(void);
+
 /*********************
  *      DEFINES
  *********************/
@@ -69,14 +71,15 @@ int main(int argc, char **argv)
   /* - lv_demo_stress(); */
   /* - lv_example_label_1(); */
   /* - etc. */
-  lv_demo_widgets();
+  /* lv_demo_widgets(); */
+  create_custom_ui();
 
   while(1) {
     /* Periodically call the lv_task handler.
      * It could be done in a timer interrupt or an OS task too.*/
     uint32_t sleep_time_ms = lv_timer_handler();
     if(sleep_time_ms == LV_NO_TIMER_READY){
-       sleep_time_ms =  LV_DEF_REFR_PERIOD;
+        sleep_time_ms =  LV_DEF_REFR_PERIOD;
     }
 #ifdef _MSC_VER
     Sleep(sleep_time_ms);
@@ -88,10 +91,49 @@ int main(int argc, char **argv)
   return 0;
 }
 
+static void create_custom_ui(void)
+{
+  lv_obj_t *scr = lv_obj_create(NULL);
+  lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE);
+  lv_scr_load(scr);
+
+  lv_obj_t *panel = lv_obj_create(scr);
+  lv_obj_set_size(panel, 360, 240);
+  lv_obj_align(panel, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_set_style_radius(panel, 18, 0);
+  lv_obj_set_style_pad_all(panel, 16, 0);
+
+  lv_obj_t *title = lv_label_create(panel);
+  lv_label_set_text(title, "My Custom Widget");
+  lv_obj_set_style_text_font(title, &lv_font_montserrat_20, 0);
+  lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 0);
+
+  lv_obj_t *status = lv_label_create(panel);
+  lv_label_set_text(status, "Default UI ready");
+  lv_obj_align_to(status, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 6);
+
+  lv_obj_t *bar = lv_bar_create(panel);
+  lv_obj_set_width(bar, 280);
+  lv_bar_set_value(bar, 64, LV_ANIM_OFF);
+  lv_obj_align_to(bar, status, LV_ALIGN_OUT_BOTTOM_MID, 0, 18);
+  lv_obj_set_style_radius(bar, 8, LV_PART_MAIN);
+  lv_obj_set_style_pad_row(bar, 12, LV_PART_MAIN);
+
+  lv_obj_t *slider = lv_slider_create(panel);
+  lv_slider_set_value(slider, 30, LV_ANIM_OFF);
+  lv_obj_set_width(slider, 280);
+  lv_obj_align_to(slider, bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 24);
+
+  lv_obj_t *btn = lv_btn_create(panel);
+  lv_obj_set_size(btn, 140, 50);
+  lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -8);
+  lv_obj_t *btn_label = lv_label_create(btn);
+  lv_label_set_text(btn_label, "Run Action");
+}
 
 #endif