pyglet เป็นไลบรารีสำหรับภาษาไพธอนเพื่อสร้างหน้าต่าง และมัลติมีเดียข้ามแพล็ตฟอร์มบนระบบปฏิบัติการวินโดวส์ (Windows) แมคโอเอส (macOS) และลินุกซ์ (Linux) สำหรับใช้พัฒนาเกมหรือแอปพลิเคชันเกี่ยวกับวิชวลไลเซชัน ตัวไลบรารีรองรับการสร้างหน้าต่าง การเชื่อมประสานกับผู้ใช้ผ่านทางระบบการทำงานตามเหตุการณ์ รองรับกราฟิกส์ของโอเพนจีแอล (OpenGL) รองรับการโหลดภาพ/วีดิทัศน์ และเล่นเสียงเพลง/ดนตรี โดยบทความนี้กล่าวถึงการติดตั้งและใช้งาน pyglet บน Raspberry Pi 3 B+ และ Raspberry Pi 4 เป็นอุปกรณ์ทดสอบบทความ
คุณสมบัติเด่นของ 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
การเรียกใช้ไลบรารี pyglet ต้องเรียกใช้ไลบรารี pyglet โดยผู้เขียนได้สร้างชื่อเรียกใหม่เป็น pg ซึ่งเขียนชุดคำสั่งสำหรับเรียกใช้ไลบรารีได้ดังนี้ และตรวจสอบรุ่นได้ดังตามตัวอย่างในภาพที่ 3
import pyglet as pg
การสร้างหน้าต่าง
การสร้างหน้าต่างของ 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
โค้ดโปรแกรมสำหรับแสดงหน้าต่าง
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()
กรณีที่ต้องการสร้างหน้าต่างแบบเต็มจอภาพ สามารถกระทำตามรูปแบบด้านบนโดยกำหนดคุณสมบัติ 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
การดักเหตุการณ์เกี่ยวกับหน้าต่าง
การดักเหตุการณ์วาดหน้าจอสามารถกระทำได้ดังนี้
การดักเหตุการณ์ที่เกิดจากการ 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
การรอดักเหตุการณ์การลากเมาส์ สามารถเขียนได้ดังนี้
โดยที่
- 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 และสุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ
แหล่งอ้างอิง
- pyglet : docs
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-08-12