UX/UI Workshops

1. ภาพรวมของ LVGL

LVGL คืออะไร?

LVGL (Light and Versatile Graphics Library) เป็น Open-source Graphics Library สำหรับระบบ Embedded ที่ต้องการสร้าง UI บนหน้าจอ

┌─────────────────────────────────────────────────────────────┐
│                    Application Layer                        │
│              (Your Code - GPIO, ADC, Sensors)               │
├─────────────────────────────────────────────────────────────┤
│                      LVGL Library                           │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐            │
│  │ Widgets │ │ Events  │ │ Styles  │ │Animation│            │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘            │
├─────────────────────────────────────────────────────────────┤
│                    Display Driver                           │
│              (Frame Buffer, VG-Lite GPU)                    │
├─────────────────────────────────────────────────────────────┤
│                      Hardware                               │
│              (LCD Display, Touch Panel)                     │
└─────────────────────────────────────────────────────────────┘

2. สถาปัตยกรรมของ LVGL

2.1 Object Model

องค์ประกอบ
คำอธิบาย
ตัวอย่าง

Screen

หน้าจอหลัก (Container สูงสุด)

lv_screen_active()

Object

วัตถุพื้นฐาน (Base class)

lv_obj_t *

Widget

วัตถุที่มี function เฉพาะทาง

Button, Label, Slider

Part

ส่วนประกอบย่อยของ Widget

MAIN, INDICATOR, KNOB

State

สถานะของ Object

DEFAULT, PRESSED, CHECKED

WHY: ทำไมต้องเข้าใจ Object Model?

  • UI ทุกตัวใน LVGL เป็น Object ที่มี Parent-Child relationship

  • การจัดการ Memory และ Layout ขึ้นอยู่กับโครงสร้างนี้

  • Event จะ propagate ตาม hierarchy

HOW: การประยุกต์ใช้จริง

CAUTION: ข้อควรระวัง

  • ห้าม delete parent ก่อน children (จะ crash)

  • Object ที่สร้างแล้วจะถูก LVGL จัดการ Memory (ห้าม free เอง)

  • Screen เดียวกันไม่ควรมี Object เกิน ~100 ตัว (performance)

Flowchart การวาง Widget


3. Basic Widgets

3.1 Label - แสดงข้อความ

ตัวอย่างจาก: examples/get_started/lv_example_get_started_1.c

Function
หน้าที่
Parameter

lv_label_create()

สร้าง Label widget

parent object

lv_label_set_text()

ตั้งค่าข้อความ

object, string

lv_label_set_text_fmt()

ตั้งค่าข้อความแบบ format

object, format, ...

lv_obj_align()

จัดตำแหน่ง

object, alignment, x_offset, y_offset

WHY: ทำไม Label สำคัญ?

  • ใช้แสดงค่าจาก Sensor (ADC, IMU, Temperature)

  • Debug output บนหน้าจอแทน UART

  • Status message ให้ผู้ใช้

CAUTION: ข้อควรระวัง Label

  • ข้อความยาวเกินไปจะ overflow (ใช้ lv_label_set_long_mode())

  • lv_label_set_text() จะ copy string ทุกครั้ง (memory allocation)

  • ใช้ lv_label_set_text_static() ถ้า string เป็น constant


3.2 Button - ปุ่มกด

ตัวอย่างจาก: examples/get_started/lv_example_get_started_2.c

WHY: ทำไม Button สำคัญ?

  • เป็น input หลักสำหรับ user interaction

  • ใช้ควบคุม GPIO (ON/OFF LED, Motor)

  • Trigger การทำงานต่างๆ (Start measurement, Reset)

HOW: เชื่อมโยงกับ GPIO จากสัปดาห์ที่ 1


3.3 Switch - สวิตช์เปิด/ปิด

ตัวอย่างจาก: examples/widgets/switch/lv_example_switch_1.c

WHY: ทำไม Switch เหมาะกับ GPIO?

  • แสดงสถานะ ON/OFF ชัดเจน

  • เหมาะกับการควบคุม Binary Output (LED, Relay, Motor)

  • User-friendly กว่า Button สำหรับ toggle state


3.4 LED Widget - แสดงสถานะ

ตัวอย่างจาก: examples/widgets/led/lv_example_led_1.c

Function
หน้าที่

lv_led_create()

สร้าง LED widget

lv_led_on()

เปิด LED (สว่างสุด)

lv_led_off()

ปิด LED (มืด)

lv_led_set_brightness()

ตั้งความสว่าง 0-255

lv_led_set_color()

ตั้งสี

WHY: ทำไมต้องมี Virtual LED?

  • แสดงสถานะ Hardware LED บนหน้าจอ

  • ใช้เมื่อ Physical LED ไม่พอ

  • สื่อสาร Status ให้ผู้ใช้ (Error, Warning, OK)


4. Event Handling

4.1 Event Callback Pattern

4.2 Event Types ที่สำคัญ

Event Code
เมื่อไหร่ถูกเรียก
ใช้กับ Widget

LV_EVENT_CLICKED

Click (Press + Release)

Button, Image

LV_EVENT_VALUE_CHANGED

ค่าเปลี่ยน

Slider, Switch, Arc

LV_EVENT_PRESSED

กดค้าง

ทุก Object

LV_EVENT_LONG_PRESSED

กดค้างนาน (>400ms)

ทุก Object

LV_EVENT_RELEASED

ปล่อย

ทุก Object

WHY: ทำไม Event-Driven สำคัญ?

  • ไม่ต้อง Polling สถานะ (ประหยัด CPU)

  • แยก Logic ออกจาก UI (Maintainable)

  • รองรับ Multiple Events บน Object เดียว

HOW: ส่ง User Data ผ่าน Event

CAUTION: ข้อควรระวัง Event

  • User Data ต้อง valid ตลอด lifetime ของ Object

  • ห้ามใช้ local variable เป็น User Data (จะหาย)

  • หลาย Event อาจเกิดพร้อมกัน (ต้องกรองด้วย code)

Functions สำหรับการวางตำแหน่ง (LVGL v9.2 API)

Functions สำหรับการกำหนดขนาด (Size Functions)

Layout Pattern สำหรับ 480x320 Screen

Pattern 1: Vertical Stacking (ใช้บ่อยที่สุด)

Pattern 2: Multiple Widgets at CENTER with Y-offset

Pattern 3: Container with Grid Layout

Widget Sizing Guidelines (แนะนำสำหรับ 800x480)

Widget Type

Recommended Size (800x480)

Notes / Recommendations

Title Label

Auto (text length)

แนะนำ Font: montserrat_32 หรือ 36 (เพื่อให้เด่นชัดบนความสูง 480px)

Button

Padding 50x25

ใช้ Padding แทนการ fix size เพื่อให้ปุ่มขยายตามขนาดตัวอักษร

LED

60x60 ถึง 120x120

ขนาด 60px เหมาะสำหรับสถานะทั่วไป, 120px สำหรับสถานะหลัก

Switch

100x50 ถึง 120x60

ปรับให้ใหญ่ขึ้นเพื่อให้กดง่าย (Touch Target ที่เหมาะสม)

Slider

Width 400-600

ความยาวควรอยู่ที่ประมาณ 50-75% ของความกว้างจอ

Bar

500x40

ปรับความหนา (Height) เป็น 40px เพื่อให้มองเห็นความก้าวหน้าชัดเจน

Arc

200x200 ถึง 350x350

ควรคงรูปทรงจัตุรัส (Square) เพื่อไม่ให้วงกลมเบี้ยว

Chart

700x400 max

ขยายให้เกือบเต็มพื้นที่หากเป็นหน้า Dashboard หลัก

Container

760x420 typical

เว้นขอบ (Margin) ด้านละ 20px เพื่อความสวยงาม

Common Background Colors (จาก Course Examples)

CAUTION: ข้อควรระวังในการวาง Layout

  1. ห้ามวาง Widget นอกขอบจอ: ค่า y ที่เกิน 319 หรือ x ที่เกิน 479 จะทำให้ widget หายไป

  2. ลำดับการสร้างสำคัญ: Widget ที่สร้างทีหลังจะอยู่ด้านบน (z-order)

  3. align_to ต้องทำหลัง base object ถูก position แล้ว:

  4. ใช้ padding แทน set_size สำหรับ Button:

  5. Container ควรปิด scroll flag:

Last updated

Was this helpful?