ภาพพื้นหลังปกบทเรียน

บทเรียน 2.4 — จอสัมผัสและ widget ตัวแรก

แผงควบคุมของทีมเราเอง: แตะบนจอแล้วไฟจริงติด

โมดูล 2 — จากจอสู่ฮาร์ดแวร์

คาถาประจำบทเรียน: จอไม่ใช่ของจริง จอคือรายงานของจริง — สองอย่างนี้ต้องตรงกันเสมอ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ย้อนกลับไปที่เมนู Controls อีกครั้ง (Eva Kit)

จอบอร์ด Eva Kit · เมนู Controls แดง เขียว น้ำเงิน แตะวงกลมบนจอ = สั่งไฟจริง สถานะบนจอต้องตรงกับหลอดเสมอ IPC หลอดจริงบน Eva Kit D3 D4 D5 ชุดบทเรียนนี้เราสร้างฝั่งซ้ายเอง

บทเรียน 1.1–1.3 เราแตะหน้านี้เล่น (บน Eva Kit — Dev Kit ไม่มีการ์ด Controls จึงไม่เคยเห็นหน้านี้ และนั่นยิ่งเป็นเหตุผลให้สร้างเอง) บทเรียน 2.1–2.3 เราสั่งไฟด้วยโค้ด gpio.led(i).on() ที่ไม่มีหน้าจอเลย

ชุดบทเรียนนี้เราจะสร้างหน้าจอแบบนี้เอง — ปุ่มบนจอที่ทีมเราวางเอง แตะแล้วหลอดไฟจริงบนบอร์ดติดจริง และรันได้ทั้งสองบอร์ด

สังเกตสามอย่างที่เดี๋ยวเราต้องทำให้ได้เอง: ปุ่มรู้ว่าถูกแตะ · ไฟจริงเปลี่ยนสถานะ · ตัวหนังสือบนจอเปลี่ยนตาม

หน้านี้ที่ดูธรรมดา ข้างในคือวงจรรับเหตุการณ์ที่เราจะเขียนเองในชุดบทเรียนนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทำไม · คืออะไร · ทำยังไง — แผนที่ของชุดบทเรียนนี้

คำถาม คำตอบของชุดบทเรียนนี้ อยู่ช่วงไหน
Why บทเรียน 2.1–2.3 กดปุ่มจริงก็สั่งไฟได้แล้ว ทำไมต้องมีปุ่มบนจออีก เพราะเครื่องที่ส่งมอบไปแล้ว คนอื่นเป็นคนใช้ และเขาเห็นแค่จอ · ทั้งสองบอร์ดมีปุ่มจริงให้ Python แตะได้ปุ่มเดียว แต่คำสั่งของเครื่องหนึ่งเครื่องมีมากกว่าหนึ่งคำสั่ง · และแผงที่รายงานไม่ตรงกับของจริง คือแผงที่หลอกคนคุมเครื่อง ครึ่งแรก · สไลด์ "สถานะบนจอ กับ สถานะจริง" และ "ใช้จริงที่ไหน"
What มีอะไรให้ใช้บ้าง โมดูล ui ทั้ง 132 ชื่อ (นับบน Eva Kit — Dev Kit มี Sprite เพิ่ม) — ตัวสร้าง widget 33 · ฟังก์ชันระดับโมดูล 8 · เสียง 2 กับค่าคงที่ของเสียงอีก 25 · ค่าคงที่อื่นอีก 63 · ชนิด Widget 1 · บวกเมธอดของ Widget อีก 38 ตัว สไลด์ฝั่งอินพุต + สไลด์บัญชี 132 ชื่อ
How ประกอบยังไงให้ใช้งานได้จริง event loop ที่เรียก ui.poll() ทุกรอบ แยกว่าเหตุการณ์มาจากใครด้วย handle แล้วสั่ง gpio.led() พร้อมเขียนบรรทัดสถานะกลับในจังหวะเดียวกัน 17 ไฟล์ตัวอย่าง (01–06 ในบทเรียน 2.5 · 07–17 ในบทเรียน 2.6) + ไฟล์ฝึกสองไฟล์

ปลายทางที่จับต้องได้ — แผงควบคุม LED สามสี แถวละ ไฟสถานะ + ปุ่มเปิด + ปุ่มปิด พร้อม "เปิดทั้งหมด" และ "ปิดทั้งหมด" ที่ถามยืนยันก่อน แตะแล้วหลอดจริงบนบอร์ดเปลี่ยนตาม พร้อมตัวเลขสรุปและบรรทัดสถานะที่ไม่เคยโกหก

บทเรียน 2.1–2.3 เราเป็นคนสั่งไฟเอง · ชุดบทเรียนนี้เราเปิดให้คนอื่นสั่งได้ โดยที่เรายังรับผิดชอบว่าจอพูดความจริง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เป้าหมายของชุดบทเรียนนี้

  1. สร้าง ui.Button, ui.Led, ui.Label, ui.MsgBox วางตำแหน่งเองได้ และรู้ว่าเมื่อไรควรปล่อยให้จอจัดวางให้
  2. เข้าใจว่า handle คืออะไร และทำไมต้องเก็บ .id() ไว้
  3. เขียน event loop ด้วย ui.poll() ที่แยกได้ว่าเหตุการณ์ไหนมาจาก widget ตัวไหน
  4. ต่อเหตุการณ์บนจอเข้ากับ gpio.led() แล้วทำให้ สถานะบนจอตรงกับหลอดไฟจริงตลอดเวลา

ปลายทางของวันนี้: แผงควบคุม LED สามสี แถวละ ไฟสถานะ + เปิด + ปิด และคำสั่งทั้งชุดที่ยืนยันก่อน ใช้งานได้จริง และมีตัวเลขสรุปกับบรรทัดสถานะที่ไม่เคยโกหก

ชุดบทเรียนนี้ยากกว่าบทเรียน 2.1–2.3 ตรงที่ของสองฝั่ง (จอกับหลอด) ต้องพูดตรงกัน ไม่ใช่แค่ทำงานได้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ปลายทางของชุดบทเรียนนี้ — แผงควบคุมที่เรากดเองได้

หน้าจอจาก BENTO Emulator ของเฉลยแผงควบคุมสัมผัสสามแถวที่คุมไฟจริง

หน้าจอจริงจากการรันโค้ดเฉลยบน BENTO Emulator ที่ 800x480 เท่าจอของทั้งสองบอร์ด — ไม่ใช่ภาพวาด ไม่ใช่ mock-up และไม่ใช่ภาพถ่ายจากบอร์ด
  • ปุ่มบนจอ แดง / เขียว / น้ำเงิน ตรงกับ LED สามสีบนบอร์ดหนึ่งต่อหนึ่ง — แผงนี้คุม "สามสี" ไม่ใช่ "ทุกดวง" (Dev Kit มีห้าดวง ดวง LED1/LED2 บนโมดูลไม่อยู่ในแผงนี้) ดัชนีดวงของแต่ละสีถามจากชื่อที่บอร์ดรายงาน
  • สีละหนึ่งแถว: ไฟสถานะ + ปุ่มเปิด + ปุ่มปิด แยกกันคนละปุ่ม · การ์ดขวามี "เปิดทั้งหมด" กับ "ปิดทั้งหมด" และ "ปิดทั้งหมด" เปิดกล่องยืนยันก่อน — เหตุผลอยู่ในสไลด์เฉลยส่วนที่สอง
  • บนการ์ดขวาคือตัวเลข "ติดอยู่ n จาก 3 ดวง" ที่เขียนทับใหม่ทุกครั้งที่ set_led() ทำงาน ไม่ใช่ข้อความที่พิมพ์ต่อท้ายไปเรื่อย ๆ

ตั้งแต่ชุดบทเรียนนี้ไป จอไม่ใช่แค่ที่พิมพ์ข้อความออก แต่เป็นทางที่คนสั่งงานเข้ามา

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

จากชุดบทเรียนก่อนหน้า — ปุ่มจริงออกไปถึงหน้าเว็บแล้ว

บทเรียน 2.1–2.3 จบที่ 07_button_to_broker.py กดปุ่มผู้ใช้บนบอร์ดหนึ่งครั้ง ได้ event หนึ่งใบที่ bento-aiot/team03/event · สถานะไฟเดินทางไปกับ telemetry เป็นจังหวะ · และหน้าเว็บ mqtt_dashboard.html ส่ง cmd กลับมาจุดไฟบนโต๊ะเราได้

บทเรียน 2.1–2.3 บทเรียน 2.4–2.6 วันนี้
ปุ่มจริงปุ่มเดียว อ่านด้วยการวนถาม และต้องกันเด้งเอง ปุ่มบนจอกี่ปุ่มก็ได้ มาเป็นเหตุการณ์ทีละรายการจาก ui.poll()
ไฟจริงเปลี่ยนเพราะปุ่มจริง ไฟจริงเปลี่ยนเพราะนิ้วแตะจอ และจอต้องบอกสถานะ ตรงกับ หลอดเสมอ
กดปุ่มจริงแล้วเว็บเห็น ส่วนขยายท้ายบทเรียน: แตะบนจอแล้วเว็บเห็น และเว็บสั่งให้แถบบนจอขยับ

โครงลูปยังเป็นตัวเดิม อ่าน → ตัดสินใจ → สั่ง → หน่วง → วนใหม่ เปลี่ยนแค่ว่าอินพุตมาจากนิ้วบนกระจก

ทีมที่ยังไม่ได้ลองไฟล์ 07 ของบทเรียน 2.1–2.3 ไม่เสียอะไร เนื้อหาหลักของวันนี้ไม่พึ่งมัน มันกลับมาอีกครั้งเฉพาะในส่วนขยายท้ายบทเรียน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทบทวนชุดบทเรียนก่อนหน้า — ของที่เราจะเอามาใช้ต่อ

บทเรียน 2.1–2.3 เราคุมฮาร์ดแวร์ด้วยโค้ดล้วน ๆ — บรรทัดที่ยังใช้ต่อทั้งหมดในชุดบทเรียนนี้ ตัดจาก s03_led_button.py ตรง ๆ

NUM_LEDS = gpio.num_leds()
...
btn = gpio.button(0)
...
for i in range(NUM_LEDS):
    gpio.led(i).off()
...
        gpio.led(led_index).off()              # ดับดวงเดิมก่อน
        led_index = (led_index + 1) % NUM_LEDS # เลื่อนไปดวงถัดไป วนกลับที่ 0 เอง
        gpio.led(led_index).on()               # จุดดวงใหม่
...
    raw = btn.is_pressed()

ดัชนีดวงของแต่ละ สี เป็นค่าที่ถามบอร์ด ไม่ใช่เลขที่จำมา — Eva: ดวง 0 แดง 1 เขียว 2 น้ำเงิน (ดวง 2 ชื่อ RGB_RED แต่ส่องน้ำเงิน) · Dev Kit: หาจากชื่อ RGB_RED / RGB_GREEN / RGB_BLUE ใน led_names (เฉลยส่วนที่หนึ่งทำให้ดู) · ปุ่มผู้ใช้มีตัวเดียว .name() คืน "USER Button 1" ไม่ใช่ป้ายบนแผ่นวงจร

ผังวงจร LED ผู้ใช้บนบอร์ด Eva Kit ที่ขับผ่านทรานซิสเตอร์ สั่ง 1 แล้วไฟติด
ภาพ: KIT_PSE84_EVAL PSOC™ Edge E84 Evaluation Kit guide, Infineon 002-39007 Rev.*B, รูปที่ 78 (หน้า 89) — ใช้เพื่อการเรียนการสอน
ภาพเคลื่อนไหว MOSFET: ช่องนำกระแสระหว่าง drain กับ source ก่อตัวตามแรงดันที่ gate
ภาพ: Stefan Riepl (Quark48), Wikimedia Commons, สาธารณสมบัติ — ช่องนำกระแส drain-source ก่อตัวตามแรงดันที่ gate ดูตอนมันเคลื่อน
ปลายทางของทุกคำสั่ง gpio.led() วันนี้ คือขา USER_LED1-3 ที่มุมซ้ายของวงจรนี้ (วงจรของ Eva Kit — Dev Kit ยังไม่ได้เปิดคู่มือตรวจ แต่ฝั่งโค้ดสั่งเหมือนกัน) — ขา MCU ขับที่ gate ของ MOSFET ไม่ได้จ่ายกระแสให้หลอดเอง แพทเทิร์นลูปเดิมยังอยู่ครบ: อ่าน input → ตัดสินใจ → สั่ง output → หน่วงเวลา → วนใหม่ ชุดบทเรียนนี้เปลี่ยนแค่แหล่ง input จาก "ปุ่มจริง" เป็น "นิ้วบนกระจก"

โครงลูปเดิม แต่ input มาจากคนละโลก — ตรงนี้แหละที่ทำให้ต้องมีกลไกใหม่ชื่อ event

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เข้าใจฮาร์ดแวร์ · ปุ่มบนจอไม่ใช่ปุ่มบนบอร์ด

ปุ่มจริงบนบอร์ดต่อสายตรงเข้าขาชิป โค้ดของเราอ่านค่าขาได้ทันทีเมื่อไรก็ได้ — นั่นคือ polling

ปุ่มบนจอไม่มีสาย มันเป็นภาพที่ CM55 วาด และนิ้วเราไปโดนตัวตรวจจับสัมผัสของจอ ซึ่งอยู่ฝั่ง CM55 ทั้งหมด ส่วนโค้ด Python ของเรารันอยู่ที่ CM33 คนละคอร์กัน

CM55 จึงต้อง จดเหตุการณ์ใส่คิวไว้ แล้วรอให้ CM33 มาถามว่า "มีอะไรใหม่ไหม" คำถามนั้นคือ ui.poll()

นิ้วแตะกระจก ตัวตรวจจับสัมผัส CM55 · LVGL รู้ว่าโดน widget ไหน เขียนลงคิวเหตุการณ์ คิวเหตุการณ์ รอ ไม่หายไปไหน CM33 · โค้ดของเรา ui.poll() มาถามเป็นรอบ ๆ แล้วสั่ง gpio.led() นิ้วเราไปถึงโค้ด Python ผ่านสี่ทอด ไม่ใช่ทอดเดียว ถ้าเราไม่ถาม คิวก็ค้าง — เหตุการณ์ไม่หาย แต่ก็ไม่มีอะไรเกิดขึ้น

ปุ่มบนบอร์ดเราไป "อ่าน" เอง ส่วนปุ่มบนจอเราต้องไป "รับของที่ฝากไว้"

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เข้าใจฮาร์ดแวร์ · ปุ่มบนจอไม่ใช่ปุ่มบนบอร์ด (ต่อ)

ภายในรถยนต์ที่ควบคุมเกือบทุกอย่างผ่านจอสัมผัสจอเดียว แผงควบคุมเครื่องจักรที่มีปุ่มกดจริงหลายปุ่มเรียงกัน

ซ้าย: ห้องโดยสารที่เหลือแต่จอสัมผัส — ของจริงที่แลกปุ่มกดทิ้งไปหมด ดูแล้วเถียงกันก่อนว่าได้อะไรและเสียอะไร — ภาพ: Oq10pass / Wikimedia Commons — CC0 1.0  |  ขวา: แผงปุ่มกดจริงของเครื่องจักร นิ้วรู้ตำแหน่งได้โดยไม่ต้องมอง นี่คือสิ่งที่ปุ่มบนจอไม่มี และเป็นเหตุผลที่บอร์ดยังเหลือปุ่มจริงไว้ — ภาพ: Elmschrat / Wikimedia Commons — CC BY-SA 3.0
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ดูเพิ่ม · กระจกแผ่นนั้นรู้ได้อย่างไรว่านิ้วมาแตะ

How do touchscreens work? · Khan Academy India
นิ้วคนคือตัวนำ พอเข้าใกล้กระจกมันเพิ่มความจุไฟฟ้าให้จุดนั้น วงจรจึงรู้ว่ามีคนแตะโดยไม่ต้องมีสวิตช์กล
Projected Capacitive Touch · Zytronic Displays
แอนิเมชันที่เห็นชัดที่สุดว่านิ้ว "ขโมย" เส้นสนามไฟฟ้าระหว่างอิเล็กโทรดสองชุดไปอย่างไร

แผงปุ่มสัมผัสแบบ capacitive ที่เห็นลายทองแดงอยู่ใต้กระจก

แผงปุ่มสัมผัสหลังกระจกจริง — ไม่มีชิ้นส่วนขยับเลยสักชิ้น มองแล้วเห็นว่าสิ่งที่อยู่ใต้กระจกคือลายทองแดง ไม่ใช่สวิตช์ — ภาพ: Zeroping / Wikimedia Commons — CC BY 4.0

ทั้งสองคลิปเป็นของนอกเวลา (ต้องมีอินเทอร์เน็ต) ไม่ต้องเปิดในบทเรียน — เนื้อหาวันนี้เข้าใจได้ครบโดยไม่ต้องดู หลักการเดียวกันนี้กลับมาอีกครั้งในบทเรียน 2.7–2.9 ตอนที่เราอ่านปุ่ม CapSense บนบอร์ดโดยตรง

จอสัมผัสไม่ได้วัด "แรงกด" มันวัด ความใกล้ของตัวนำ — จำประโยคนี้ไว้ ชุดบทเรียนถัดไปใช้ซ้ำ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ห้าขั้นของการสร้าง widget หนึ่งตัว

แพทเทิร์นนี้ยกมาจากคอร์สภาษา C ที่เราเคยสอน — บน MicroPython โค้ดสั้นลงมาก แต่ ลำดับความคิดเหมือนเดิมทุกขั้น

1 · สร้าง ui.Button(...) 2 · วางที่ x, y, w, h 3 · หน้าตา text, color 4 · จำเบอร์ btn.id() 5 · กรอง type == 'clicked' ห้าขั้นนี้เรียงตายตัว ข้ามขั้นไหนก็พังคนละแบบ ขั้น 1-3 คือ "ของที่เห็น" · ขั้น 4-5 คือ "ของที่ตอบสนอง"
ขั้น ในภาษา C (LVGL ดิบ) ในโค้ดของเรา
1 สร้างตัว widget lv_button_create(parent) btn = ui.Button("แดง")
2 กำหนดตำแหน่ง lv_obj_align(...) x=20, y=110 ตอนสร้าง หรือ .pos(x, y)
3 ใส่ข้อความ/หน้าตา สร้าง label ลูกแล้ว lv_label_set_text text="แดง", color=0xE53935
4 ผูกเหตุการณ์ lv_obj_add_event_cb(btn, cb, ...) เก็บ btn.id() ไว้เทียบใน ui.poll()
5 กรองชนิดเหตุการณ์ if(code == LV_EVENT_CLICKED) if ev['type'] == 'clicked'

ขั้น 4 ต่างกันที่สุด: C ฝาก callback ไว้ให้ระบบเรียก ส่วนเราเก็บ หมายเลขประจำตัว ไว้เช็กเองในลูป

จำห้าขั้นนี้ให้ขึ้นใจ ทุก widget ที่เหลือในคอร์ส (Slider, Arc, Chart) ใช้ลำดับเดียวกันหมด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

สร้าง widget: พารามิเตอร์ที่ใช้บ่อย

import ui
ui.screen()                                    # ล้างของเก่าทั้งหน้าก่อนเริ่มเสมอ

title = ui.Label("แผงควบคุมของทีม", x=20, y=20, color=0xFFFFFF, value=24)
btn   = ui.Button("แดง", x=20, y=110, w=170, h=80, color=0xE53935)
sw    = ui.Switch(x=620, y=120)
(0,0) มุมซ้ายบนของ Playground x = 20 → ขวา y = 110 → ลง แดง w = 170 h = 80 กำหนดเอง = ออกแบบไว้ x = -1 · ปล่อยให้จอเรียงให้ เรียงตามลำดับที่สร้าง คุมตำแหน่งไม่ได้
  • x, y มุมซ้ายบนเป็นพิกเซล · w, h ถ้าไม่ใส่ จอเลือกขนาดพอดีข้อความให้เอง
  • color สีเป็นเลขฐานสิบหก 0xRRGGBB แบบเดียวกับ CSS
  • x=-1 (ค่าเริ่มต้น) = auto-layout — ปล่อยให้จอเรียงให้ เหมาะกับตอนลองของเร็ว ๆ ไม่เหมาะกับแผงควบคุม

แผงควบคุมจริงต้องกำหนด x, y เอง เพราะ "ปุ่มอยู่ตรงไหน" เป็นส่วนหนึ่งของการออกแบบ ไม่ใช่เรื่องบังเอิญ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

กับดักที่คนพลาดกันทุกรุ่น: value= คือขนาดฟอนต์

ui.Label("อุณหภูมิ", value=24)      # 24 = ตัวอักษรสูง 24 พิกเซล ไม่ใช่ค่า 24 องศา
ui.Button("แดง", value=20)          # ตัวหนังสือบนปุ่มขนาด 20
Label · Button · Dropdown · Textarea value=14 ข้อความตัวอย่าง value=16 ข้อความตัวอย่าง value=20 ข้อความตัวอย่าง value=24 ข้อความตัวอย่าง value=28 · เกินห้าค่านี้ไม่รับ Slider · Arc · Bar value คือ "ค่าจริง" ตามชื่อ min=0 max=100 value=45 ตัวนี้เท่านั้นที่ value = ตัวเลขที่วัดได้

สำหรับ Label, Button, Dropdown, Textarea พารามิเตอร์ value= หมายถึง ขนาดฟอนต์ และรับได้แค่ห้าค่า: 14 / 16 / 20 / 24 / 28

ส่วน min, max, value ที่เป็น "ค่าจริง" ตามชื่อ ใช้กับ Slider, Arc, Bar เท่านั้น (บทเรียน 2.7–2.9 กับ 3.1–3.3 เราจะได้ใช้)

อยากเปลี่ยนข้อความของ Label ให้ใช้เมธอด .text("ข้อความใหม่") เสมอ ไม่ใช่ value=

เห็น value= ที่ Label เมื่อไร ให้อ่านในใจว่า "ขนาดตัวอักษร" ทันที จะไม่พลาดอีกเลย

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

handle — บัตรประจำตัวของ widget

ตอนสร้าง widget สิ่งที่เราได้กลับมาคือ ตัวจัดการ (handle) ที่ผูกกับ widget จริงบน CM55 อีกฝั่งหนึ่ง

btn_red = ui.Button("แดง", x=20, y=110, w=170, h=80)
red_id  = btn_red.id()          # หมายเลขประจำตัว ใช้เทียบตอนรับเหตุการณ์
แดง เขียว น้ำเงิน .id() = 3 .id() = 4 .id() = 5 สิ่งที่ ui.poll() คืนมา {'handle': 4, 'type': 'clicked'} เหตุการณ์ไม่ได้บอกชื่อปุ่ม มันบอกแค่เบอร์ ไม่มีชื่อ ไม่มีสี ไม่มีข้อความ — มีแต่เบอร์

เหตุการณ์ที่ ui.poll() คืนมาไม่ได้บอกว่า "ปุ่มแดงถูกกด" มันบอกแค่ หมายเลข ว่า widget เบอร์นี้ถูกกด งานของเราคือจำไว้ว่าเบอร์ไหนคือใคร

วิธีที่สะอาดที่สุดเมื่อมีปุ่มหลายตัวคือเก็บเป็น list แล้วใช้ .index() หาลำดับ

on_ids = [b.id() for b in btn_on]
i = on_ids.index(ev['handle'])     # ได้ 0, 1 หรือ 2 = แถวไหน (แดง เขียว น้ำเงิน)

ถ้าไม่เก็บ .id() ไว้ ตอนเหตุการณ์เข้ามาเราจะแยกไม่ออกเลยว่าใครเป็นคนส่ง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0