[TH] PyGlet

pyglet เป็นไลบรารีสำหรับภาษาไพธอนเพื่อสร้างหน้าต่าง และมัลติมีเดียข้ามแพล็ตฟอร์มบนระบบปฏิบัติการวินโดวส์ (Windows) แมคโอเอส (macOS) และลินุกซ์ (Linux) สำหรับใช้พัฒนาเกมหรือแอปพลิเคชันเกี่ยวกับวิชวลไลเซชัน ตัวไลบรารีรองรับการสร้างหน้าต่าง การเชื่อมประสานกับผู้ใช้ผ่านทางระบบการทำงานตามเหตุการณ์ รองรับกราฟิกส์ของโอเพนจีแอล (OpenGL) รองรับการโหลดภาพ/วีดิทัศน์ และเล่นเสียงเพลง/ดนตรี โดยบทความนี้กล่าวถึงการติดตั้งและใช้งาน pyglet บน Raspberry Pi 3 B+ และ Raspberry Pi 4 เป็นอุปกรณ์ทดสอบบทความ

ภาพที่ 1 ตัวอย่างจาก 1-6

คุณสมบัติเด่นของ pyglet

  • ไม่ต้องใช้ไลบรารีเพิ่มเติมภายนอก
  • รองรับการแสดงผลแบบหลายหน้าต่างและหลายจอแสดงผล
  • รองรับรูปแบบของภาพ เสียง ดนตรี และวีดิทัศน์ ซึ่งสามารถเรียกใช้ ffmpeg เพื่อเล่นไฟล์ MP3 OGG/Vorbis WMA DivX MPEG-2 H.264 WMV และ Xvid
  • ใช้ลิขสิทธิ์เปิดเผยโค้ดแบบ BSD (BSD open-source license)
  • ทำงานเข้ากันได้กับไพธอนรุ่น 2 และ 3

การติดตั้งไลบรารีกระทำผ่านทาง pip ด้วยคำสั่งต่อไปนี้ และตัวอย่างหน้าจอการติดตั้งเป็นดังภาพที่ 2

pip install pyglet

ภาพที่ 2 ตัวอย่างการติดตั้ง pyglet

การเรียกใช้ไลบรารี pyglet ต้องเรียกใช้ไลบรารี pyglet โดยผู้เขียนได้สร้างชื่อเรียกใหม่เป็น pg ซึ่งเขียนชุดคำสั่งสำหรับเรียกใช้ไลบรารีได้ดังนี้ และตรวจสอบรุ่นได้ดังตามตัวอย่างในภาพที่ 3

import pyglet as pg

ภาพที่ 3 เรียกใช้และแสดงรุ่นของ pyglet

การสร้างหน้าต่าง

การสร้างหน้าต่างของ pyglet ต้องเรียกใช้คลาส window เพื่อสร้างหน้าต่างของแอปพลิเคชันดังภาพที่ 4 โดยรูปแบบการใช้งานดังต่อไปนี้

โดยที่

  • width คือ ความกว้างของหน้าต่างที่ต้องการสร้าง
  • height คือ ความสูงของหน้าต่างที่ต้องการสร้าง
  • caption คือ ข้อความส่วนหัวของหน้าต่าง หรือที่เรียกว่า title ซึ่งเป็นค่าที่ไม่จำเป็นต้องกำหนด และสามารถกำหนดหรือเปลี่ยนแปลงในภายหลังได้ด้วยคำสั่งเปลี่ยนข้อความส่วนหัวของหน้าต่าง
  • resizable คือ การกำหนดให้หน้าต่างที่สร้างมีคุณสมบัติถูกปรับเปลี่ยนขนาดได้หรือไม่ โดย True หมายถึงสามารถปรับเปลี่ยนขนาดได้ และ False หมายถึงไม่สามารถปรับเปลี่ยนขนาดได้
  • visible คือ การกำหนดค่าให้หน้าต่างที่สร้างปรากฏบนหน้าจอแสดงผลหรือไม่ โดย True หมายถึง หน้าต่างปรากฏบนหน้าจอหลังจากสั่งสร้างหน้าต่างสำเร็จ และ False หมายถึง ให้ซ่อนหน้าต่างไว้หลังจากสร้างหน้าต่างสำเร็จ และผู้ใช้สามารถสั่งแสดงหน้าต่างด้วย set_visible( True ) ในภายหลัง
  • style คือ รูปแบบของหน้าต่างซึ่งมี 3 ประเภท (ดังภาพที่ 4, 5 และ 6) ดังนี้
    • pg.window.Window.WINDOW_STYLE_DEFAULT
    • pg.window.Window.WINDOW_STYLE_DIALOG
    • pg.window.Window.WINDOW_STYLE_TOOL
ภาพที่ 4 หน้าต่างของแอปพลิเคชัน

โค้ดโปรแกรมสำหรับแสดงหน้าต่าง

import pyglet as pg
win = pg.window.Window(width=320,height=240, 
        caption='Pyglet Ex1-1', 
        style=pg.window.Window.WINDOW_STYLE_TOOL)

@win.event
def on_draw():
    win.clear()
if __name__=='__main__':
    pg.app.run()
ภาพที่ 5 หน้าต่างแบบ pg.window.Window.WINDOW_STYLE_DEFAULT
ภาพที่ 6 หน้าต่างแบบ pg.window.Window.WINDOW_STYLE_DIALOG
ภาพที่ 7 หน้าต่างแบบ pg.window.Window.WINDOW_STYLE_TOOL

กรณีที่ต้องการสร้างหน้าต่างแบบเต็มจอภาพ สามารถกระทำตามรูปแบบด้านบนโดยกำหนดคุณสมบัติ fullscreen=True เพิ่มเข้าไปพารามิเตอร์ของคำสั่งสร้างหน้าต่าง แต่อย่างไรก็ดี ผู้เขียนโปรแกรมสามารถสั่งตั้งค่าหน้าต่างให้เป็นหน้าต่างแบบเต็มจอหรือหน้าต่างปกติได้ด้วยคำสั่งตามรูปแบบต่อไปนี้

โดยที่

  • fullscreen เป็น True หมายถึงเปลี่ยนโหมดการแสดงผลเป็นเต็มจอแสดงผล และ ถ้าเป็น False เป็นการแสดงในรูปแบบหน้าต่างปกติ
  • screen ถ้าไม่ใช่ค่า None และ fullscreen เป็น True แล้วหน้าต่างจะย้ายไปยังหน้าจอนั้น และใช้หน้าจอนั้นเป็นหน้าจอแสดงผลแบบเต็มจอ
  • mode ถ้ากำหนดเป็น None โหมดแสดงผลจะเปลี่ยนความกว้างและความสูงตามที่กำหนดให้ค่าของ width และ height
  • width เป็นค่าความกว้างของจอแสดงผลหรือหน้าต่าง
  • height เป็นค่าความสูงของจอแสดงผลหรือหน้าต่าง

การสร้างหน้าต่างแบบหลายจอแสดงผลต้องดำเนินการ 3 ขั้นตอน คือ ร้องขอค่าอ้างอิงจอแสดงผล ร้องขอข้อมูลสกรีน (screen) ทั้งหมด และดำเนินการสร้างหน้าต่าง โดยโค้ดตัวอย่างต่อไปนี้เป็นการสร้างหน้าต่างแบบเต็มจอภาพในทุกจอแสดงผล

การสร้างหน้าต่างโดยกำหนดคุณสมบัติของโอเพนจีแอลสามารถเขียนเป็นโค้ดได้ดังนี้

import pyglet as pg
# 1 เตรียมค่าคอนฟิก
ตัวแปรคอนฟิก  = pg.gl.Config( )
# 2 ตั้งค่าคอนฟิก
ตัวแปรคอนฟิก.aux_buffers = 4
ตัวแปรคอนฟิก.stereo = 0
ตัวแปรคอนฟิก.sample_buffers = 0
ตัวแปรคอนฟิก.red_size = 8
ตัวแปรคอนฟิก.green_size = 8
ตัวแปรคอนฟิก.blue_size = 8
ตัวแปรคอนฟิก.alpha_size = 8
ตัวแปรคอนฟิก.depth_size = 8
ตัวแปรคอนฟิก.stencil_size = 0
ตัวแปรคอนฟิก.accum_red_size = 0
ตัวแปรคอนฟิก.accum_green_size = 0
ตัวแปรคอนฟิก.accum_blue_size = 0
ตัวแปรคอนฟิก.accum_alpha_size = 0
ตัวแปรคอนฟิก.major_version = 3
ตัวแปรคอนฟิก.minor_version = 3
ตัวแปรคอนฟิก.forward_compatible = False
ตัวแปรคอนฟิก.debug = False
# 3 สร้างหน้าต่าง
ตัวแปรอ้างอิงหน้าต่าง = pg.window.Window(config=ตัวแปรคอนฟิก)

คำสั่งสำหรับสั่งงานหน้าต่างให้หน้าต่างเปลี่ยนเป็นสถานะเป็นหน้าต่างบนสุด เป็นดังนี้

ตัวแปรอ้างอิงหน้าต่าง.activate( )

คำสั่งสำหรับล้างหน้าจอมีรูปแบบการใช้งานดังนี้

ตัวแปรอ้างอิงหน้าต่าง.clear( )

คำสั่งสำหรับสั่งปิดหน้าต่าง เป็นดังนี้

ตัวแปรอ้างอิงหน้าต่าง.close( )

คำสั่งสำหรับวาดเคอร์เซอร์ของเมาส์มีรูปแบบการใช้งานดังนี้

ตัวแปรอ้างอิงหน้าต่าง.draw_mouse_cursor( )

คำสั่งสำหรับสลับหน้าจอกับบัฟเฟอร์ในกรณีที่สร้างหน้าต่างเป็นแบบดับเบิลบัฟเฟอร์ (double buffer) เป็นดังนี้ ซึ่งคำสั่ง flip( ) จะถูกเรียกให้ทำงานหลังจากได้ทำคำสั่งต่าง ๆ ที่ผู้เขียนโปรแกรมกำหนดไว้ในเหตุการณ์ on_draw เสมอ เนื่องจากการทำงานของ pyglet เป็นแบบดับเบิลบัฟเฟอร์ ดังนั้น จึงไม่จำเป็นต้องเรียกใช้งานคำสั่งนี้

ตัวแปรอ้างอิงหน้าต่าง.flip( )

คำสั่งสำหรับตั้งค่าพิกัด (x,y) ปัจจุบันของหน้าต่างบนจอแสดงผล และคำสั่งอ่านพิกัดปัจจุบันของหน้าต่างบนจอแสดงผล สามารถใช้งานได้ตามรูปแบบต่อไปนี้

คำสั่งสำหรับอ่านค่าความกว้างและความสูงของหน้าต่างกับคำสั่งกำหนดขนาดของหน้าต่างมีรูปแบบของการใช้งานดังนี้

คำสั่งสำหรับกำหนดขนาดของหน้าต่างขนาดใหญ่สุด ขนาดของหน้าต่างเล็กสุด และการเปลี่ยนสถานการณ์แสดงผลเป็นหน้าต่างขนาดใหญ่และหน้าต่างขนาดเล็ก มีรูปแบบการสั่งงานดังนี้

การกำหนดไอคอนของหน้าต่างด้วยภาพขนาด 16×16 32×32 บนระบบปฏิบัติการ Windows และขนาด 16×16 32×32 64×64 และ 128×128 บนระบบปฏิบัติการ macOS โดยคำสั่งมีรูปแบบดังนี้

ตัวแปรอ้างอิงหน้าต่าง.set_icon( *images )

โดยที่

image ได้จากการโหลดภาพจากไฟล์ เช่น

  • icon16x16 = pg.image.load(’16×16.png’)
  • icon32x32 = pg.image.load(’32×32.png’)

ตัวแปรอ้างอิงหน้าต่าง.set_icon(icon16x16, icon32x32)

หมายเหตุ
1.ไอคอนที่เปลี่ยนไม่ใช่ภาพไอคอนของแอปพลิเคชัน แต่เป็นการเปลี่ยนไอคอนของหน้าต่างเมื่อแอปพลิเคชันทำงาน
2.ไฟล์นามสกุล .ico ใช้ได้เฉพาะบนระบบปฏิบัติการ Windows เท่านั้น ดังนั้น กรณีที่พัฒนาแอปพลิเคชันข้ามระบบปฏิบัติการควรเลือกใช้ไฟล์ไอคอนจากไฟล์ภาพ PNG เนื่องจากเป็นไฟล์ภาพที่รองรับค่าความโปร่งแสง

คำสั่งสำหรับปรับเปลี่ยนข้อความในส่วนของหัวหน้าต่างมีรูปแบบของการใช้งานดังนี้

ตัวแปรอ้างอิงหน้าต่าง.set_caption( text )

สั่งสำหรับเปิดหรือปิดการควบคุมเมาส์ โดยถ้าตั้งค่าเป็น True จะป้องกันไม่ให้เมาส์ออกจากขอบเขตของหน้าต่าง ซ่อนการแสดงเคอร์เซอร์ และสามารถอ่านค่าได้เฉพาะค่า (dx, dy) ซึ่งเป็นค่าความเปลี่ยนแปลงในแกน x และ y เมื่อเกิด motion ซึ่งคำสั่งมีรูปแบบดังนี้

ตัวแปรอ้างอิงหน้าต่าง.set_exclusive_mouse(exclusive=True)
ตัวแปรอ้างอิงหน้าต่าง.set_exclusive_mouse(exclusive=False)

คำสั่งสำหรับเปิดหรือปิดการควบคุมแป้นพิมพ์ โดยถ้ากำหนดเป็น True จะเป็นการป้องกันไม่ให้ผู้ใช้สามารถสลับหน้าต่างไปมากับแอปพลิเคชันอื่น ๆ ได้ ซึ่งรูปแบบคำสั่งเป็นดังนี้

ตัวแปรอ้างอิงหน้าต่าง.set_exclusive_keyboard( exclusive=True )
ตัวแปรอ้างอิงหน้าต่าง.set_exclusive_keyboard( exclusive=False )

คำสั่งสำหรับอ่านภาพของเคอร์เซอร์เมาส์ และตั้งค่าภาพเคอร์เซอร์เมาส์มีรูปแบบของคำสั่งดังนี้

ตัวแปรเมาส์เคอร์เซอร์ = ตัวแปรอ้างอิงหน้าต่าง.get_system_cursor( name )
ตัวแปรอ้างอิงหน้าต่าง.set_mouse_cursor(cursor)

โดยที่

  • name เป็นชื่อของประเภทของเคอร์เซอร์ที่ต้องการอ่านซึ่งเป็นตามตารางที่ 1-1 และชื่อของค่าคงที่/ชื่อเรียกของเคอร์เซอร์เป็นดังนี้
    • CURSOR_CROSSHAIR= ‘crosshair’
    • CURSOR_DEFAULT= None
    • CURSOR_HAND= ‘hand’
    • CURSOR_HELP= ‘help’
    • CURSOR_NO= ‘no’
    • CURSOR_SIZE= ‘size’
    • CURSOR_SIZE_DOWN= ‘size_down’
    • CURSOR_SIZE_DOWN_LEFT= ‘size_down_left’
    • CURSOR_SIZE_DOWN_RIGHT= ‘size_down_right’
    • CURSOR_SIZE_LEFT= ‘size_left’
    • CURSOR_SIZE_LEFT_RIGHT= ‘size_left_right’
    • CURSOR_SIZE_RIGHT= ‘size_right’
    • CURSOR_SIZE_UP= ‘size_up’
    • CURSOR_SIZE_UP_DOWN= ‘size_up_down’
    • CURSOR_SIZE_UP_LEFT= ‘size_up_left’
    • CURSOR_SIZE_UP_RIGHT= ‘size_up_right’
    • CURSOR_TEXT= ‘text’
    • CURSOR_WAIT= ‘wait’
    • CURSOR_WAIT_ARROW= ‘wait_arrow’
  • cursor เป็นค่าเมาส์เคอร์เซอร์ ปกติกำหนดเป็น None

คำสั่งสำหรับซ่อน/แสดงเคอร์เซอร์เมาส์กระทำได้ด้วยคำสั่งต่อไปนี้

ตัวแปรอ้างอิงหน้าต่าง.set_mouse_visible( visible=False )
ตัวแปรอ้างอิงหน้าต่าง.set_mouse_visible( visible=True )

การสั่งให้เกิดการซ่อน/แสดงหน้าต่างทำได้ดังนี้

ตัวแปรอ้างอิงหน้าต่าง.set_visible( visible=False )
ตัวแปรอ้างอิงหน้าต่าง.set_visible( visible=True )

ค่าคุณสมบัติของหน้าต่าง

คุณสมบัติหรือแอททริบิวต์ (attribute) ของคลาสหน้าต่างมีดังนี้

  • caption เป็นข้อความของหัวหน้าต่าง สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • config เป็นค่าคอนฟิกเพื่ออธิบายบริบทของโอเพนจีแอล สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว ซึ่งเป็นคุณสมบัติตามคลาส pg.gl.Config
  • context เป็นค่าบริบทของโอเพนจีแอล สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว ซึ่งเป็นคุณสมบัติตามคลาส pg.gl.Context
  • display เป็นค่าการแสดงผล สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • fullscreen เป็นค่าสถานะของหน้าต่าง ถ้าเป็น True หมายถึงแสดงผลแบบเต็มจอภาพ และถ้าเป็น False หมายถึงแสดงในรูปแบบของหน้าต่าง สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • height เป็นค่าความสูงของหน้าต่าง สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • width เป็นค่าความกว้างของหน้าต่าง สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • resizable เป็นค่าสถานะของหน้าต่าง ถ้าเป็น True หมายถึงหน้าต่างสามารถปรับขนาดได้ แต่ถ้าเป็น False หมายถึง ไม่สามารถปรับขนาดของหน้าต่างได้ สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • screen ค่าสกรีนของหน้าต่าง สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • style เป็นค่ารูปแบบของหน้าต่าง ซึ่งมีค่าตามนี้
    • WINDOW_STYLE_BORDERLESS= ‘borderless’
    • WINDOW_STYLE_DEFAULT= None
    • WINDOW_STYLE_DIALOG= ‘dialog’
    • WINDOW_STYLE_TOOL= ‘tool’
      สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • visible เป็นค่าสถานการณ์ปรากฏของหน้าต่าง ถ้ามีค่าเป็น True หมายถึง หน้าต่างแสดงผลอยู่ แต่ถ้าเป็น False หมายถึงหน้าต่างถูกซ่อน สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว
  • vsymc เป็นค่าสถานะของการทำ V-Sync โดยถ้ามีค่าเป็น True หมายถึง การแสดงผลของหน้าต่างทำงานตามค่า V-Sync และถ้าเป็น False หมายถึง หน้าต่างไม่ได้ทำงานตาม V-Sync สามารถเข้าถึงแบบอ่านได้เพียงอย่างเดียว

ตารางที่ 1-1 เคอร์เซอร์เมาส์ในระบบปฏิบัติการ Windows XP และ Mac OS X (ที่มา https://pyglet.readthedocs.io/en/stable/programming_guide/mouse.html)

เหตุการณ์

เหตุการณ์ (event) คือ สิ่งที่เกิดขึ้นในระบบปฏิบัติการ โดยผู้เขียนโปรแกรมมีหน้าที่คอยตรวจสอบเหตุการณ์ที่เกิดขึ้นในระบบว่ามีเหตุการณ์ใดเป็นของโปรแกรมที่เราเขียน และเหตุการณ์ที่เกิดขึ้นนั้นเราต้องการตอบสนองกลับไปหรือไม่ ดังภาพที่ 8

ภาพที่ 8 ระบบขับเคลื่อนด้วยเหตุการณ์

การดักเหตุการณ์เกี่ยวกับหน้าต่าง

การดักเหตุการณ์วาดหน้าจอสามารถกระทำได้ดังนี้

การดักเหตุการณ์ที่เกิดจากการ active ของหน้าต่างสามารถกระทำได้ดังนี้

การดักเหตุการณ์ที่เกิดจากสูญเสียการ active ของหน้าต่างสามารถกระทำได้ดังนี้

การดักเหตุการณ์ที่เกิดจากการสั่งซ่อนหน้าต่าง สามารถกระทำได้ดังนี้

การดักเหตุการณ์ที่เกิดจากการสั่งปิดหน้าต่างสามารถกระทำได้ดังนี้

การรอดักเหตุการณ์การแสดงหน้าต่าง (หลังจากซ่อน) สามารถเขียนได้ดังนี้

การรอดักเหตุการณ์การเลื่อนหน้าต่าง สามารถเขียนได้ดังนี้

โดยที่ x, y ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ

การดักเหตุการณ์กรณีของการสูญเสีย context ของ OpenGL ซึ่งมีผลทำให้ไม่สามารถเรียกใช้ชุดคำสั่งของโอเพนจีแอลได้ สามารถกระทำได้ดังนี้

การดักเหตุการณ์กรณีสถานะของบริบทโอเพนจีแอลของหน้าต่างหายไป (context state lost) เมื่อเกิดการย้ายหน้าต่างไปยังอุปกรณ์แสดงผลอื่น หรือเกิดการเปลี่ยนแปลงบริบทไปมาระหว่างการแสดงผลเต็มจอและหน้าต่าง หรือเปลี่ยนจากหน้าต่างเป็นแสดงผลเต็มจอ ซึ่งผู้เขียนโปรแกรมอาจจะต้องเก็บสถานะของรายการ (lists) ลายผิว และเฉดเดอร์ (shader) ระหว่างบริบทเก่าและบริบทใหม่ สามารถกระทำได้ดังนี้

การรอดักเหตุการณ์การปรับขนาดของหน้าต่าง สามารถเขียนได้ดังนี้

โดยที่

  • width คือ ความกว้างของหน้าต่างหลังจากมีการปรับขนาดแล้ว
  • height คือ ความสูงของหน้าต่างหลังจากปรับขนาดแล้ว

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

pg.app.run( )

จากรูปแบบของคำสั่งที่กล่าวมาทั้งหมดสามารถเขียนเป็นตัวอย่างโปรแกรมสร้างหน้าต่างขนาด 800×600 พร้อมกำหนดข้อความหัวหน้าต่างเป็น Pyglet Ex1-1 และสามารถออกจากโปรแกรมด้วยการกดแป้น ESC เขียนได้ดังตัวอย่างโปรแกรมที่ 1-1

import pyglet as pg
win = pg.window.Window(width=800,height=600, caption='Pyglet Ex1-1')

@win.event
def on_draw():
    win.clear()
if __name__=='__main__':
    pg.app.run()

การดักเหตุการณ์จากแป้นพิมพ์

แป้นพิมพ์เป็นหน่วยนำเข้าข้อมูลหลักของคอมพิวเตอร์ ซึ่งข้อมูลที่นำเข้ามาจากแป้นพิมพ์ประกอบด้วย ข้อมูลตัวอักษรที่ถูกกด เรียกกว่า symbol และข้อมูลสถานะแป้นพิเศษที่ถูกกด เรียกว่า modifier โดยข้อมูลแบบ symbol เป็นข้อมูลตัวเลขจำนวนเต็มของรหัส ASCII ของตัวอักษรที่กด ซึ่งมีค่าเป็นค่าคงที่ภายใต้คลาส pg.window.key ดังนี้

  • กลุ่มของตัวอักษร ได้แก่
  • กลุ่มของตัวเลข ได้แก่
  • กลุ่มของแป้นฟังก์ชัน ได้แก่
  • กลุ่มของแป้นควบคุม ได้แก่
  • กลุ่มของแป้นตัวเลข (Num Lock) ได้แก่
  • ข้อมูล modifier เป็นตัวเลขจำนวนเต็มที่แต่ละบิตบ่งบอกสถานะของแป้นพิเศษที่กด โดยมีค่าเป็นตามรายการในคลาส pg.window.key ดังนี้

ลำดับของเหตุการณ์เมื่อมีการกดแป้นพิมพ์และปล่อยแป้นพิมพ์ 1 ครั้ง ประกอบด้วย 3 ลำดับเหตุการณ์เรียงจากก่อนไปหลัง คือ on_key_press( ) on_text(text) หรือ on_text_motion(motion) หรือ on_text_motion_select(motion) และ on_key_release( )

การรอดักเหตุการณ์การกดแป้นพิมพ์จากผู้ใช้ สามารถเขียนได้ดังนี้

โดยที่

  • symbol เป็นค่าสัญลักษณ์ของแป้นที่กด
  • modifiers เป็นค่าบิตของแป้น shift, ctrl, alt ที่กดพร้อมกับ symbol ตัวอย่างการเขียนโค้ดตรวจสอบเป็นดังนี้
if modifers & pg.window.key.MOD_SHIFT:
     pass

การดักข้อมูลตัวอักษรที่ผู้ใช้กด ซึ่งเป็นเหตุการณ์ที่เกิดหลัง on_key_press และก่อน on_key_release สามารถเขียนได้ดังนี้

การดักข้อมูลตัวอักษรที่ผู้ใช้เลื่อนตำแหน่งเคอร์เซอร์ของตัวอักษร ซึ่งเป็นเหตุการณ์ที่เกิดหลัง on_key_press และก่อน on_key_release สามารถเขียนได้ดังนี้

โดยที่

motion เป็นค่าใดต่อไปนี้ภายใต้ pg.window.key

  • MOTION_UP
  • MOTION_RIGHT
  • MOTION_DOWN
  • MOTION_LEFT
  • MOTION_NEXT_WORD
  • MOTION_PREVIOUS_WORD
  • MOTION_BEGINNING_OF_LINE
  • MOTION_END_OF_LINE
  • MOTION_NEXT_PAGE
  • MOTION_PREVIOUS_PAGE
  • MOTION_BEGINNING_OF_FILE
  • MOTION_END_OF_FILE
  • MOTION_BACKSPACE
  • MOTION_DELETE

การดักข้อมูลตัวอักษรที่ผู้ใช้กเลื่อนตำแหน่งเคอร์เซอร์ของตัวอักษรในเหตุการณ์การเลือก ซึ่งเป็นเหตุการณ์ที่เกิดหลัง on_key_press และก่อน on_key_release สามารถเขียนได้ดังนี้

โดยที่

motion เป็นค่าใดต่อไปนี้ภายใต้ pg.window.key

  • MOTION_UP
  • MOTION_RIGHT
  • MOTION_DOWN
  • MOTION_LEFT
  • MOTION_NEXT_WORD
  • MOTION_PREVIOUS_WORD
  • MOTION_BEGINNING_OF_LINE
  • MOTION_END_OF_LINE
  • MOTION_NEXT_PAGE
  • MOTION_PREVIOUS_PAGE
  • MOTION_BEGINNING_OF_FILE
  • MOTION_END_OF_FILE

การรอดักเหตุการณ์การปล่อยแป้นพิมพ์จากผู้ใช้ สามารถเขียนได้ดังนี้

โดยที่

  • symbol เป็นค่าสัญลักษณ์ของแป้นที่ถูกปล่อย
  • modifiers เป็นค่าบิตของแป้น shift, ctrl, alt ที่กดพร้อมกับ symbol

ตัวอย่างโปรแกรมที่ 1-2 เป็นการสร้างหน้าต่างขนาด 800×600 และมีการตอบสนองการกดแป้น F เพื่อสลับไปมาระหว่างโหมดหน้าต่างแบบเต็มจอและโหมดหน้าต่างปกติ โดยทำการตรวจสอบในบรรทัดที่ 14 ซึ่งคำสั่ง ord( ) ใช้สำหรับการแปลงอักขระให้เป็นค่า ASCII ของตัวอักขระที่ส่งเป็นพารามิเตอร์ หรือเปลี่ยนเป็น if (symbol == pg.window.key.F):

import pyglet as pg

win = pg.window.Window(width=800,height=600)
win.set_caption("PyGlet Ex1-2")
bFullScreen = False

@win.event
def on_draw():
    win.clear()

@win.event
def on_key_press( symbol, modifiers ):
    global bFullScreen
    if (symbol == ord('f')):
        if (bFullScreen):
            bFullScreen = False
        else:
            bFullScreen = True
        win.set_fullscreen( bFullScreen )

if __name__=='__main__':
    pg.app.run()

การดักเหตุการณ์จากการเคลื่อนที่ของเมาส์

เมาส์เป็นอุปกรณ์นำเข้าข้อมูล โดยให้ข้อมูลพิกัดตำแหน่งของเคอร์เซอร์เมาส์เป็นพิกัด (x,y) และสามารถตรวจสอบการกดปุ่มเมาส์ได้ 3 ประเภท (ดังภาพที่ 9) คือ

  • pg.window.mouse.LEFT
  • pg.window.mouse.RIGHT
  • pg.window.mouse.MIDDLE
ภาพที่ 9 ปุ่มของเมาส์

การรอดักเหตุการณ์การลากเมาส์ สามารถเขียนได้ดังนี้

โดยที่

  • x, y คือ ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ
  • dx,dy คือ ค่าทิศทางการเคลื่อนที่ในแกน x และ y
  • buttons คือ เป็นค่าของปุ่มของเมาส์ที่กด
  • modifiers คือ ค่า modifiers ที่กดพร้อมกับ buttons

การรอดักเหตุการณ์ที่เมาส์เลื่อนเข้ามาในหน้าต่างของแอปพลิเคชัน สามารถเขียนได้ดังนี้

โดยที่ x, y ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ

การรอดักเหตุการณ์ที่เมาส์เลื่อนออกจากหน้าต่างของแอปพลิเคชัน สามารถเขียนได้ดังนี้

การรอดักเหตุการณ์การขยับเมาส์ สามารถเขียนได้ดังนี้

โดยที่

  • x, y ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ
  • dx,dy ค่าทิศทางการเคลื่อนที่ในแกน x และ y

การรอดักเหตุการณ์การกดเมาส์ สามารถเขียนได้ดังนี้

โดยที่

  • x, y ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ
  • buttons เป็นค่าของปุ่มของเมาส์ที่กด
  • modifiers เป็นค่าบิตของแป้น shift, ctrl, alt ที่กดพร้อมกับ buttons

การรอดักเหตุการณ์การสกรอลล์เมาส์ สามารถเขียนได้ดังนี้

โดยที่

  • x, y ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ
  • scroll_x, scroll_y เป็นค่าของสครอลล์ในแกน x และ y

การรอดักเหตุการณ์การปล่อยการกดเมาส์ สามารถเขียนได้ดังนี้

โดยที่

  • x, y ค่าพิกัดที่ห่างจากมุมซ้ายบนของจอ
  • buttons เป็นค่าของปุ่มของเมาส์ที่กด
  • modifiers เป็นค่าบิตของแป้น shift, ctrl, alt ที่กดพร้อมกับ buttons

ตัวอย่างโปรแกรมที่ 1-3 เป็นตัวอย่างการดักเหตุการณ์จากการคลิกเมาส์ หรือ on_mouse_presss() เพื่อทำการเปลี่ยนเคอร์เซอร์ของเมาส์ด้วยการคลิกขวา โดยสร้างตัวแปร cursors เพื่อเก็บค่าคงที่ของเคอร์เซอร์ระบบในแบบต่าง ๆ เมื่อผู้ใช้คลิกขวาจะอ่านข้อมูลภาพเคอร์เซอร์ลำดับที่ current_cursor มาเก็บในตัวแปร cursor ด้วยคำสั่ง get_system_mouse_cursor() หลังจากนั้นดำเนินการเปลี่ยนภาพเคอร์เซอร์ด้วยคำสั่ง set_mouse_cursor พร้อมทั้งมีการเพิ่มค่าของ current_cursor ขึ้น 1 ค่า แต่ถ้าพบว่าตัวแปร current_cursor มีค่ามากกว่าลำดับสุดท้าย (เก็บในตัวแปร last_cursor) ของตัวแปรจะกำหนดค่าของ current_cursor ให้เป็น 0

import pyglet as pg

win = pg.window.Window(width=800,height=600)
win.set_caption("PyGlet Ex1-3")
win.set_mouse_visible(True)
cursors = [win.CURSOR_CROSSHAIR, win.CURSOR_DEFAULT, win.CURSOR_HAND, win.CURSOR_HELP, win.CURSOR_NO, win.CURSOR_SIZE, win.CURSOR_SIZE_DOWN, win.CURSOR_SIZE_DOWN_LEFT, win.CURSOR_SIZE_DOWN_RIGHT, win.CURSOR_SIZE_LEFT, win.CURSOR_SIZE_LEFT_RIGHT, win.CURSOR_SIZE_RIGHT, win.CURSOR_SIZE_UP, win.CURSOR_SIZE_UP_DOWN, win.CURSOR_SIZE_UP_LEFT, win.CURSOR_SIZE_UP_RIGHT, win.CURSOR_TEXT, win.CURSOR_WAIT, win.CURSOR_WAIT_ARROW]
current_cursor = 0
last_cursor = len(cursors)

@win.event
def on_draw():
    win.clear()

@win.event
def on_mouse_press(x,y,buttons,modifers):
    global cursors
    global current_cursor
    global last_cursor
    if (buttons == pg.window.mouse.RIGHT):
        cursor = win.get_system_mouse_cursor(cursors[current_cursor])
        win.set_mouse_cursor(cursor)
        current_cursor = current_cursor + 1
        if current_cursor>=last_cursor:
            current_cursor = 0

if __name__=='__main__':
    print(last_cursor)
    pg.app.run()

ตัวอย่างโปรแกรมที่ 1-4 เป็นการสร้างคลาส MyWindow เพื่อสืบทอดคุณสมบัติของคลาส pg.window.Window โดยสร้างหน้าต่างขนาด 640×480 มีข้อความที่หัวหน้าต่างเป็น Pyglet Ex1-4 และทำการเปิดโหมด exclusive ของเมาส์และแป้นพิมพ์ เมื่อกดแป้น R เป็นการเปลี่ยนสีฉากหลังเป็นสีแดง อันเป็นสีที่ผสมกันระหว่างค่าสีแบบ RGB คือ 1.0, 0.0, 0.0 และ 1.0 เมื่อกดแป้น G เปลี่ยนสีฉากหลังเป็นสีเขียว และกดแป้น B เปลี่ยนสีฉากหลังเป็นน้ำเงิน และออกจากการทำงานเพื่อผู้ใช้กดแป้น Q

import pyglet as pg
from pyglet import gl

class MyWindow(pg.window.Window):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.set_size(640,480)
        self.set_caption("Pyglet Ex1-4")
        self.set_exclusive_mouse(True)
        self.set_exclusive_keyboard(True)

    def on_draw(self):
        self.clear()
    
    def on_key_press( self, symbol, modifers ):
        if symbol == pg.window.key.Q:
            self.close()
        elif symbol == pg.window.key.R:
            gl.glClearColor(1.0,0.0,0.0,1.0)
        elif symbol == pg.window.key.G:
            gl.glClearColor(0.0,1.0,0.0,1.0)
        elif symbol == pg.window.key.B:
            gl.glClearColor(0.0,0.0,1.0,1.0)

if __name__=='__main__':
    win = MyWindow()
    pg.app.run()

การแสดงข้อความ

การแสดงข้อความต้องใช้คลาส text ของ pyglet โดยรูปแบบของการสร้างข้อความเป็นดังนี้

โดยที่

  • ข้อความ คือ สายอักขระข้อความที่ต้องการสร้าง
  • x, y คือ ตำแหน่ง (x,y) ในหน้าต่าง
  • bold คือ การเปิดปิดคุณสมบัติการเป็นตัวอักษรหนา ถ้าเป็น True หมายถึงข้อความแสดงด้วยตัวอักษรตัวหนา แต่ถ้าเป็น False เป็นตัวอักษรปกติ
  • italic คือ การเปิดปิดคุณสมบัติการเป็นตัวอักษรเอียง โดยถ้ากำหนดเป็น True หมายถึง ข้อความที่สร้างเป็นตัวอักษรเอียง และถ้าเป็น False หมายถึงเป็นตัวอักษรปกติ
  • font_name คือ ชื่อฟอนต์ของข้อความ เช่น ‘Tahoma’ ‘TH Saraban New’ เป็นต้น
  • font_size คือ ขนาดของฟอนต์ มีค่าหน่วยเป็น pt
  • color คือ สีของตัวอักษร ซึ่งต้องการกำหนดเป็นค่าสีแบบ RGBA โดยแต่ละสีมีค่าเป็น 0-255 เช่น ต้องการกำหนดตัวอักษรเป็นสีเหลือง ต้องกำหนดค่าเป็น color=(255,255,0,255) และกรณีที่ต้องการสร้างตัวอักษรสีเขียวต้องกำหนดค่าสีดังนี้ color=(0,255,0,255) เป็นต้น
  • anchor_x คือ วิธีการจัดเรียงข้อความในแกน X ซึ่งกำหนดเป็นค่าใดค่าหนึ่งดังนี้ ‘left’ , ‘right’ , ‘center’
  • anchor_y คือ วิธีการตัดเรียงข้อความในแกน Y ซึ่งกำหนดเป็นค่าใดค่าหนึ่งดังนี้ ‘baseline’ , ‘center’

กรณีที่ต้องการสร้างข้อมูลโดยใช้รูปแบบการสร้างตามแท็กภาษา HTML สามารถดำเนินการโดยใช้รูปแบบของคำสั่งดังต่อไปนี้

โดยที่

  • ข้อความ คือ สายอักขระข้อความที่ต้องการสร้างภายใต้รูปแบบของแท็กภาษา HTML เช่น
    ‘<font face=”Tahoma” size=”12pt”><B>Hi</B></font>’
  • x, y คือ ตำแหน่ง (x,y) ในหน้าต่าง
  • anchor_x คือ วิธีการจัดเรียงข้อความในแกน X ซึ่งกำหนดเป็นค่าใดค่าหนึ่งดังนี้ ‘left’ , ‘right’ , ‘center’
  • anchor_y คือ วิธีการตัดเรียงข้อความในแกน Y ซึ่งกำหนดเป็นค่าใดค่าหนึ่งดังนี้ ‘baseline’ , ‘center’

คำสั่งแสดงแสดงตัวแปรข้อความที่สร้างไว้ที่จอแสดงผล มีรูปแบบการใช้งานดังนี้

ตัวแปรข้อความ.draw( )

ตัวอย่างโปรแกรมที่ 1-5 เป็นการแสดงข้อความ Hello, World สีเหลือง จากฟอนต์ Tahoma ขนาด 12 พอยต์ เป็นตัวอักษรหนาและเอียงที่กึ่งกลางหน้าต่าง และในตัวอย่างที่ 1-6 เป็นการแสดง Hello, World จากการใช้แท็กภาษา HTML ที่มีลักษณะเดียวกับตัวอย่าง 1-5 แต่จะพบว่า การทำงานของตัวอย่าง 1-6 ช้ากว่า 1-5 เนื่องจากต้องถอดรหัสภาษา HTML ให้เป็นข้อมูลคำสั่ง

import pyglet as pg

win = pg.window.Window(width=640,height=480)
win.set_caption("Pyglet Ex1-5")
xCenter = win.width//2
yCenter = win.height//2
text="Hello, World"
txtHello = pg.text.Label(text, font_name="Tahoma", bold=True, italic=True, font_size=12, x=xCenter, y=yCenter, anchor_x='center', anchor_y='center', color=(255,255,0,255))

@win.event
def on_draw():
    win.clear()
    txtHello.draw()

if __name__=='__main__':
    pg.app.run()

ตัวอย่างโปรแกรมที่ 1-6 แสดงข้อความจากแท็ก HTML

import pyglet as pg

win = pg.window.Window(width=640,height=480)
win.set_caption("Pyglet Ex1-6")


xCenter = win.width//2
yCenter = win.height//2
text="<font face='Tahoma' size=12pt color=#FFFF00><b><i>Hello, World</i></b></font>"
txtHello = pg.text.HTMLLabel(text, x=xCenter, y=yCenter, anchor_x='center', anchor_y='center')

@win.event
def on_draw():
    win.clear()
    txtHello.draw()

if __name__=='__main__':
    pg.app.run()

การแสดงภาพ

คำสั่งสำหรับโหลดภาพจากไฟล์ภาพมาเก็บในตัวแปร มีรูปแบบการใช้งานดังนี้

ตัวแปรข้อมูลภาพ = pg.image.load( ชื่อภาพ )

โดยที่ ชื่อภาพ คือ ชื่อของไฟล์ภาพ ซึ่งระบบปฏิบัติการ Windows สามารถเปิดไฟล์นามสกุล

  • BMP
  • DDS
  • EXIT
  • GIF
  • JPG
  • JPEG
  • PNG
  • TIF
  • และ TIFF

สำหรับระบบปฏิบัติการ macOS/Linux รองรับไฟล์ภาพประเภท

  • BMP
  • DDS
  • GIF
  • JPG
  • JPEG
  • JP2
  • JPX
  • PCX
  • PNG
  • TGA
  • TIF
  • TIFF
  • XBM
  • และ XPM

ข้อมูลความกว้างและความสูงของภาพสามารถใช้จากค่าคุณสมบัติของตัวแปรข้อมูลภาพตามรูปแบบต่อไปนี้

ตัวแปรข้อมูลภาพ.width
ตัวแปรข้อมูลภาพ.height

การนำภาพไปแสดงสามารถกระทำโดยการใช้คำสั่งดังรูปแบบต่อไปนี้

ตัวแปรข้อมูลภาพ.blit( x, y, z )

โดยที่

  • x, y คือ ตำแหน่งพิกัด (x,y) ในหน้าต่างที่ใช้เป็นจุดแสดงภาพ
  • z คือ ค่าลำดับชั้นความลึกของภาพ

กรณีที่ต้องแปลงข้อมูลภาพเพื่อใช้เป็นลายผิว (Texture) สำหรับโอเพนจีแอลสามารถทำได้ด้วยการแปลงรูปแบบของข้อมูลดังนี้

ตัวแปรลายผิว = ตัวแปรข้อมูลภาพ.get_texture( )

ตัวอย่างโค้ดการนำตัวแปรลายผิวไปใช้ เป็นดังนี้

from pyglet  import  gl
gl.glEnable( ตัวแปรลายผิว.target )
gl.glBindTexture( ตัวแปรลายผิว.target, ตัวแปรลายผิว.id )

การเข้าถึงข้อมูลภายในตัวแปรข้อมูลภาพต้องดำเนินการแปลงข้อมูลเป็นข้อมูลดิบตามรูปแบบของคำสั่งต่อไปนี้

คำสั่งสำหรับตัดส่วนของภาพจากตำแหน่ง (x,y) กว้าง width และสูง height สามารถกระทำได้ตามรูปแบบต่อไปนี้

ตัวแปรภาพตัดส่วน = ตัวแปรข้อมูลภาพ.get_region( x, y, width, height )

การบันทึกตัวแปรข้อมูลภาพลงไฟล์ภาพ สามารถใช้คำสั่งตามรูปแบบต่อไปนี้

ตัวแปรข้อมูลภาพ.save( filename )

ภาพแบบกริด (image grid) เป็นเทคนิคการโหลดภาพและแบ่งภาพที่โหลดเข้ามาเป็นหลายชิ้น ทำให้ผู้พัฒนาสามารถเตรียมภาพหลายภาพเก็บไว้ในภาพใหญ่ภาพเดียว ทำให้ประหยัดเวลาในการเข้าถึงไฟล์ภายหลาย ๆ ไฟล์ เนื่องจากไม่ต้องสูญเสียเวลาการร้องขอ I/O หลายรอบ รูปแบบของคำสั่งสร้างภาพแบบกริดเป็นดังนี้

ตัวแปรภาพแบบกริด = pg.image.ImageGrid( ตัวแปรข้อมูลภาพ, row, col )

โดยที่

  • row คือ จำนวนแถวของภาพแบบกริด
  • col คือ จำนวนคอลัมน์ในแถว

สรุป

จากบทความนี้จะพบว่า PyGlet เป็นชุดพัฒนาที่รองรับการทำ GUI และเชื่อมประสานกับ OpenGL ได้ค่อนข้างดีกว่าการใช้ PyGame และเป็นไลบรารีที่ไม่ต้องการติดตั้งไลบรารีเสริมอื่น พร้อมทั้งรองรับทั้งการบริหารจัดการกับหน้าต่างแสดงผล การตอบสนองจากผู้ใช้ผ่านทางแป้นพิมพ์ หรือเมาส์ นอกจากนี้ยังรองรับรูปภาพที่หลากหลาย พร้อมทั้งสามารถแสดงข้อความด้วยรูปแบบอักษรจากฟอนต์แบบ True Type ทำให้สะดวกในการนำไปประยุกต์ใช้งาน สุดท้ายนี้ ผวังว่าบทความคงมีประโยชน์ต่อผู้ที่สนใจเขียน GUI บนระบบปฏิบัติการของ Windows, macOS หรือ Linux และสุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

แหล่งอ้างอิง

  1. pyglet : docs

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ

ปรับปรุงเมื่อ 2021-08-12