Button

Lab 2: Button with Click Counter

1. โครงสร้างภาพรวมของ Lab

Why?: วัตถุประสงค์การเรียนรู้

Button เป็น Widget พื้นฐานที่สำคัญที่สุดสำหรับการรับ Input จากผู้ใช้:

  • User Interaction: Button เป็นวิธีหลักที่ผู้ใช้โต้ตอบกับ GUI

  • GPIO Control: ใช้ควบคุม GPIO เช่น เปิด/ปิด LED, Motor

  • Action Trigger: ใช้สั่งเริ่ม/หยุดการทำงานต่างๆ

  • Event-Driven: เรียนรู้แนวคิด Event-driven Programming

What?: จะได้เรียนรู้อะไร

  1. Button Widget: สร้างปุ่มกดด้วย lv_button_create()

  2. Event Callback: ผูก callback function กับ event

  3. Event Filtering: กรอง event ที่ต้องการด้วย LV_EVENT_CLICKED

  4. Static Variable: เก็บค่า counter ข้าม function calls

  5. Child Widget: เพิ่ม Label ลงใน Button

ฟังก์ชัน
หน้าที่

lv_button_create()

สร้าง Button widget

lv_obj_add_event_cb()

ผูก Event callback function

lv_event_get_code()

ดึง event code ภายใน callback

lv_event_get_target()

ดึง object ที่ถูกกด

lv_event_get_user_data()

ดึง user data ที่ส่งมากับ event

LV_EVENT_CLICKED

Event เมื่อกดและปล่อยปุ่ม

How? - ทำอย่างไร

  • สร้างปุ่มที่นับจำนวนครั้งที่กด และแสดงผลบน Label ภายในปุ่ม


2. หลักการทำงานและ Flowchart

2.1 Event-Driven Model

2.2 Button Creation Pattern (LVGL Official)

circle-exclamation

2.3 Program Flowchart


3. ฟังก์ชันสำคัญ (API Reference)

3.1 Button Creation & Style

ฟังก์ชัน
พารามิเตอร์
คำอธิบาย

lv_button_create(parent)

parent object

สร้าง Button ใหม่

lv_obj_set_style_pad_hor(btn, px, part)

btn, pixels, 0

padding ซ้าย-ขวา (ทำให้ปุ่มกว้าง)

lv_obj_set_style_pad_ver(btn, px, part)

btn, pixels, 0

padding บน-ล่าง (ทำให้ปุ่มสูง)

lv_obj_set_style_bg_color(btn, color, part)

btn, lv_color_t, 0

สีพื้นหลังปุ่ม

lv_obj_set_style_radius(btn, r, part)

btn, pixels, 0

มุมมนของปุ่ม

3.2 Event Functions

ฟังก์ชัน
พารามิเตอร์
คำอธิบาย

lv_obj_add_event_cb(obj, cb, filter, data)

obj, callback_fn, LV_EVENT_*, user_data

ลงทะเบียน event callback

lv_event_get_code(e)

lv_event_t *

ดึง event code

lv_event_get_target(e)

lv_event_t *

ดึง object ที่เกิด event

lv_event_get_user_data(e)

lv_event_t *

ดึง user data ที่ส่งมา

3.3 Common Event Codes

Event Code
เมื่อไหร่
ใช้เมื่อ

LV_EVENT_CLICKED

กดแล้วปล่อย (tap สมบูรณ์)

ใช้บ่อยที่สุด - สำหรับ action ทั่วไป

LV_EVENT_PRESSED

นิ้วแตะลง

ตอบสนองทันที ไม่รอปล่อย

LV_EVENT_RELEASED

ยกนิ้วขึ้น

ใช้คู่กับ PRESSED

LV_EVENT_LONG_PRESSED

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

สำหรับ action พิเศษ

LV_EVENT_VALUE_CHANGED

ค่าเปลี่ยน

สำหรับ Slider, Switch, Dropdown

3.4 Label Functions ใน Button

ฟังก์ชัน
คำอธิบาย

lv_label_create(btn)

สร้าง Label เป็น child ของ Button

lv_obj_center(label)

วาง Label ตรงกลาง Button

lv_obj_get_child(btn, 0)

ดึง child แรก (Label) จาก Button

lv_label_set_text_fmt(label, fmt, ...)

อัปเดตข้อความของ Label


4. โค้ดตัวอย่าง (Code Examples)

4.1 โค้ดอ้างอิง: part1_ex2_button_counter()

จากไฟล์ part1_examples.c:

วิเคราะห์จุดสำคัญ:

จุด
โค้ด
ทำไม

Event filter

LV_EVENT_CLICKED ใน add_event_cb

ลงทะเบียนเฉพาะ CLICKED

Static counter

static uint32_t cnt = 0

เก็บค่าข้าม function call

Get child label

lv_obj_get_child(btn, 0)

ดึง Label จาก Button

Update text

lv_label_set_text_fmt()

อัปเดตข้อความแบบ dynamic

Padding

pad_hor(30), pad_ver(15)

ใช้แทน set_size()

user_data

NULL

ไม่ส่ง data เพราะมีปุ่มเดียว

4.2 Button กับ User Data

4.3 Multiple Callbacks กับ Multiple Buttons

4.4 Button Style Customization


5. องค์ความรู้และเทคนิค

5.1 Event Filter: ทำไมต้อง Filter?

เหตุผล: LV_EVENT_ALL จะเรียก callback ทุกครั้งที่มี event ใดๆ เกิดขึ้น (หลายสิบครั้งต่อ touch เดียว) ทำให้สิ้นเปลือง CPU และอาจเกิดปัญหาที่ไม่คาดคิด

5.2 ข้อผิดพลาดที่พบบ่อย

ข้อผิดพลาด
สาเหตุ
วิธีแก้

ปุ่มเล็กเกินไป

ใช้ lv_obj_set_size() กับ Button

ใช้ lv_obj_set_style_pad_hor/ver() แทน

Label หายจากปุ่ม

สร้าง Label ก่อน set_size

สร้าง Label หลังสุด แล้ว lv_obj_center()

Callback ไม่ทำงาน

ลืม add_event_cb หรือ event code ผิด

ตรวจสอบ filter event

Counter กลับเป็น 0

ตัวแปร local ไม่ใช่ static

ประกาศ static

user_data เป็น garbage

ส่ง address ของ local variable

ใช้ static variable หรือ global

กด 1 ครั้ง callback เรียกหลายครั้ง

ใช้ LV_EVENT_ALL

ใช้ LV_EVENT_CLICKED

5.3 ขนาดปุ่มที่แนะนำสำหรับ Touch Screen

5.4 Static Variables vs. Global Variables


6. แบบฝึกหัด (Exercises)

Exercise 1: Increment/Decrement Counter - 10-15 นาที

โจทย์: สร้าง Counter ที่มีปุ่ม 2 ตัว สำหรับเพิ่ม (+1) และลด (-1) ค่า

ข้อกำหนด:

  1. Background สี 0x1a1a2e

  2. Title "Production Counter" (font_24, สีขาว, TOP_MID)

  3. Label แสดงค่า counter เริ่มที่ 0 (font_24, สีขาว, CENTER, y=-30)

  4. ปุ่ม "+" สีเขียว อยู่ทางซ้าย (CENTER, x=-80, y=+40)

  5. ปุ่ม "-" สีแดง อยู่ทางขวา (CENTER, x=+80, y=+40)

  6. ค่า counter ไม่ต่ำกว่า 0 (ถ้า counter == 0 แล้วกด "-" ไม่ลด)

  7. แสดง format "Count: XX"

Expected Output:

Hints:

  • ใช้ static int สำหรับ counter

  • สร้าง global label pointer สำหรับแสดงค่า

  • ใช้ user_data ส่ง direction (+1 หรือ -1)


Exercise 2: Toggle Button (Medium)

สร้างปุ่มที่สลับระหว่าง "ON" และ "OFF" เมื่อกด พร้อมเปลี่ยนสีปุ่ม

Expected Output:

Hints:

  • ใช้ static bool state = false;

  • lv_obj_set_style_bg_color() เปลี่ยนสีปุ่ม


Exercise 3: Long Press Detection (Advanced)

สร้างปุ่มที่แยกการกดสั้นและกดค้าง:

  • กดสั้น: แสดง "Short Press"

  • กดค้าง 1 วินาที: แสดง "Long Press"

Hints:

  • ใช้ LV_EVENT_CLICKED และ LV_EVENT_LONG_PRESSED

  • สามารถ register หลาย callback ได้


7. References


Next Lab: Lab 3: LED Widget Control

Last updated

Was this helpful?