فى هذه الجزئية سنتحدث عن الإشارات والأحداث.
كل تطبيقات الواجهات مسيرة بالأحداث، وكذلك PyGTK. تبدأ التطبيقات عند حلقة ال main بإستدعاء gtk.main التى تقوم بإستمرار بفحص الأحداث اللتى تم توليدها، اذا لم يكن هناك اى حدث ينتظر التطبيق ولايفعل شئ.
الأحداث هى رسائل من خادم إكس للتطبيق، اذا ضغطنا على زر، يتم ارسال الإشارة clicked، هناك اشارات ايضا ترثها كل الويدجات مثل destroy وهنا اشارات خاصة بويدجت معين مثل toggled لل ToggleButton
يستخدم المبرمجين معالج الإشارة -signal handler- ليتفاعل مع الإشارات المختلفة، يسمى ال signal handler بإسم callback فى عالم ال GTK
handler_id = button.connect("clicked", self.on_clicked)هنا لدينا الطريقة connect التابعة للصف Gobject (الgtkButton هو Gobject )، لنربط معالج الإشارة self.on_clicked بالإشارة المسماه clicked
الطريقة connect تعيد لنا handler id وهى قيمة فريدة تستخدم للتعرف على معالج الحدث، نستطيع ان نستخدم ذلك المعرف id مع الطرق التالية
def disconnect(handler_id) def handler_disconnect(handler_id) def handler_is_connected(handler_id) def handler_block(handler_id) def handler_unblock(handler_id)
تسمحلنا هذه الطرق بفصل معالج الحدث او عمل block/unblock له
يوجد عادة الكثير من الحيرة حولهم، الإشارة والحدث هما شيئين مختلفين تماما، الحدث هو عبارة عن تمثيل 1 الى 1 لأحداث نظام النافذة، الضغط على مفتاح، اعادة تحجيم نافذة، او الضغط على زر هما احداث لنظام النوافذ، ويتم تبليغها فى حلقة ال main ، تعالج ال GDK تلك الأحداث وتقوم بتمريرها من خلال الإشارات.
الإشارة، هى ليست اكثر من ميكانيكية للإستدعاء العكسى، اذا اراد احد الكائنات ان يتم اعلامه عن اى فعل لكائن اخر اوتغيير فى حالته، فنقوم بتسجيل callback او اكثر واستدعاءها/استدعائهم لإشارة ما، وايضا تستطيع ارسال بعض البيانات المحددة معها.
الإشارات هى اطار اعلام -تبليغ- عام الهدف، ليس فقط اعلامات حول تغييرات الواجهة، ولكن ربما عند تغيير الحالة ايضا، فهى عامة وقوية ويستخدمو على مدى واسع. اى كائن من الصف GObject يستطيع ارسال/استقبال اشارات، ممكن للنوع ان يكون له اكثر من اشارة، كل منها لها معاملاتها وايضا القيمة المرجعية -ال return value- ، وممكن ان نقوم بربط كائناتها بمعالجات -handlers- ، عندما يتم اطلاق اشارة على كائن ما، يتم اطلاق كل المعالجات اللتى تم ربطها.
الصلة الوحيدة بين الإشارة والحدث، هو ان الإشارات تستخدم لإرسال اعلامات -تبليغات- حول الأحداث من خادم إكس
اخيرا، الإشارت هى ميزة للصف gtk.Object وكل مايرثه، والأحداث هى مفاهيم مرتبطة ب GDK/XLib
فى المثال التالى سنشرح كيفية التفاعل مع اشارتين اساسيتين.
quitbutton.py #!/usr/bin/python # ZetCode PyGTK tutorial # # The example shows how to work with # destroy and clicked signals # # author: jan bodnar # website: zetcode.com # last edited: February 2009 import gtk class PyApp(gtk.Window): def __init__(self): super(PyApp, self).__init__() self.set_title("Quit Button") self.set_size_request(250, 200) self.set_position(gtk.WIN_POS_CENTER) self.connect("destroy", self.on_destroy) fixed = gtk.Fixed() quit = gtk.Button("Quit") quit.connect("clicked", self.on_clicked) quit.set_size_request(80, 35) fixed.put(quit, 50, 50) self.add(fixed) self.show_all() def on_destroy(self, widget): gtk.main_quit() def on_clicked(self, widget): gtk.main_quit() PyApp() gtk.main()
الإشارة destroy يتم اطلاقها عند محاولة غلق النافذة -افتراضيا لاينتهى البرنامج عندما نضغط على زر الإغلاق للنافذة! -
self.connect("destroy", self.on_destroy)الطريقة connect تربط الإشارة destroy بالطريقة on_destroy
quit.connect("clicked", self.on_clicked)بالضغط على زر quit ، يتم اطلاق الإشارة clicked والتى بدورها تستدعى الطريقة on_click
def on_destroy(self, widget): gtk.main_quit()
فى الطريقة on_destroy ، نتفاعل مع الإشارة destroy، ونقوم بإنهاء عمل التطبيق بإستدعائنا الطريقة gtk.main_quit
def on_clicked(self, widget): gtk.main_quit()
هنا فى الطريقة on_clicked تأخذ معاملين، widget هو الكائن اللذى اطلق الإشارة، فى حالتنا هذه هو الزر quit ، الكائنات المختلفة ترسل إشارات مختلفة، الإشارات ومعاملاتها تستطيع ان تجدها فى مرجع PyGTK
pygtk.org/docs/pygtk/index.html
فى المثال التالى سننئ ونرسل اشارة خاصة
customsignal.py #!/usr/bin/python # ZetCode PyGTK tutorial # # This example shows how to create # and send a custom singal # # author: jan bodnar # website: zetcode.com # last edited: February 2009 import gobject class Sender(gobject.GObject): def __init__(self): self.__gobject_init__() gobject.type_register(Sender) gobject.signal_new("z_signal", Sender, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) class Receiver(gobject.GObject): def __init__(self, sender): self.__gobject_init__() sender.connect('z_signal', self.report_signal) def report_signal(self, sender): print "Receiver reacts to z_signal" def user_callback(object): print "user callback reacts to z_signal" if __name__ == '__main__': sender = Sender() receiver = Receiver(sender) sender.connect("z_signal", user_callback) sender.emit("z_signal")
انشأنا كائني GObjects ، المرسل والمستقبل. المرسل يقوم بإرسال الإشارة ليستقبلها المستقبل. وايضا نقوم بربط callback بالإشارة
class Sender(gobject.GObject): def __init__(self): self.__gobject_init__()
المرسل، يتم انشاءه بالمشيد الإفتراضى.
gobject.type_register(Sender) gobject.signal_new("z_signal", Sender, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ())
نسجل الكائن الجديد والإشارة، الطريقة signal_new تسجل اشارة مسماه z_signal للكائن Sender ، المعامل SIGNAL_RUN_FIRT يعنى ان المعالج الإفتراضى يتم استدعاءه اولا. اخر معاملين، هو القيمة المرجعيه -return value- ومعامل الأنواع. فى مثالنا لانقوم بإرجاع اى قيمة، ولا نرسل اى معاملا
sender.connect('z_signal', self.report_signal)المستقبل يستمع للإشارة z_signal وسيعالجها بإستخدام الطريقة self.report_signal
sender = Sender() receiver = Receiver(sender)
انشاء كائنات المرسل والمستقبل ، لاحظ ان المستقبل يأخذ المرسل كمعامل ليستمع اليه
sender.connect("z_signal", user_callback)هنا نربط الإشارة بمعالجها user_callback
sender.emit("z_signal")ارسال الإشارة z_signal
class Sender(gobject.GObject): __gsignals__ = { 'z_signal': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self): self.__gobject_init__() gobject.type_register(Sender)
ايضا نستطيع استخدام السمة __gsignals__ لنسجل اشارتنا الجديدة.
الكائنات فى PyGTK قد يكون لديها معالجات اشارة افتراضيه، تبدأ بمقطع do_ مثل do_expose و do_show و do_clicked
move.py #!/usr/bin/python # ZetCode PyGTK tutorial # # This example overrides predefined # do_configure_event() signal handler # # author: jan bodnar # website: zetcode.com # last edited: February 2009 import gtk import gobject class PyApp(gtk.Window): __gsignals__ = { "configure-event" : "override" } def __init__(self): super(PyApp, self).__init__() self.set_size_request(200, 150) self.set_position(gtk.WIN_POS_CENTER) self.connect("destroy", gtk.main_quit) self.show_all() def do_configure_event(self, event): title = "%s, %s" % (event.x, event.y) self.set_title(title) gtk.Window.do_configure_event(self, event) PyApp() gtk.main()
عندما ننقل او نعيد تحجيم النافذة، يرسل خادم إكس احداث configure ، اللتى يتم تحويلها لإشارات configure-event
فى مثالنا، نعرض احداثيات ال س، ص لأعلى يسار النافذة بشريط العنوان. ببساطة نستطيع ان نربط الإشارة configure-event بمعالج حدث ما، ولكننا سنسلك استراتيجية مشتركة، سنقوم بإعادة تعريف المعالج الإفتراضى
__gsignals__ = { "configure-event" : "override" }
هذا يعنى اننا سنقوم بإعادة تعريف الطريقة on_configure_event
def do_configure_event(self, event): title = "%s, %s" % (event.x, event.y) self.set_title(title) gtk.Window.do_configure_event(self, event)
هنا نقوم بإعادة تعريف do_configure_event ، نضع احداثيات س، ص على شريط العنوان. لاحظ ايضا فى السطر الأخير نستدعى معالج الحدث الإفتراضى للأب -جرب تشغيل التطبيق بدونه لترى ماذا سيحدث :D -
Figure: Configure singal
فى المثال التالى سنعرض مجموعة من الإشارات المختلفة للأزرار
buttonsignals.py #!/usr/bin/python # ZetCode PyGTK tutorial # # This program shows various signals # of a button widget # It emits a button-release-event which # triggers a released singal # # author: jan bodnar # website: zetcode.com # last edited: February 2009 import gtk class PyApp(gtk.Window): def __init__(self): super(PyApp, self).__init__() self.set_title("Signals") self.set_size_request(250, 200) self.set_position(gtk.WIN_POS_CENTER) self.connect("destroy", gtk.main_quit) fixed = gtk.Fixed() self.quit = gtk.Button("Quit") self.quit.connect("pressed", self.on_pressed) self.quit.connect("released", self.on_released) self.quit.connect("clicked", self.on_clicked) self.quit.set_size_request(80, 35) fixed.put(self.quit, 50, 50) self.add(fixed) self.show_all() self.emit_signal() def emit_signal(self): event = gtk.gdk.Event(gtk.gdk.BUTTON_RELEASE) event.button = 1 event.window = self.quit.window event.send_event = True self.quit.emit("button-release-event", event) def on_clicked(self, widget): print "clicked" def on_released(self, widget): print "released" def on_pressed(self, widget): print "pressed" PyApp() gtk.main()
يستطيع الزر اطلاق اكثر من اشارة واحدة، سنعمل على ثلاثه منهم clicked, released, pressed ، سنعرض ايضا كيف تطلق اشارة حدث ما اشارة اخرى
self.quit.connect("pressed", self.on_pressed) self.quit.connect("released", self.on_released) self.quit.connect("clicked", self.on_clicked)
نقوم بتسجيل معالجات الإشارة للإشارات الثلاثة
self.emit_signal()عند بداية التطبيق نقوم بإرسال إشارة محددة،
def emit_signal(self): event = gtk.gdk.Event(gtk.gdk.BUTTON_RELEASE) event.button = 1 event.window = self.quit.window event.send_event = True self.quit.emit("button-release-event", event)
نرسل اشارة button-release-event ، اللتى تأخذ كائن Event كمعامل لها بعد بداية التطبيق، يفترض ان نرى كلمة released فى نافذة الأوامر، عندما نضغط على الزر يتم اطلاق ال3 اشارات.
نستطيع ان نمنع معالج إشارة، كما فى المثال التالى.
block.py #!/usr/bin/python # ZetCode PyGTK tutorial # # This example shows how to block/unblock # a signal handler # # author: jan bodnar # website: zetcode.com # last edited: February 2009 import gtk class PyApp(gtk.Window): def __init__(self): super(PyApp, self).__init__() self.set_title("Blocking a callback") self.set_size_request(250, 180) self.set_position(gtk.WIN_POS_CENTER) fixed = gtk.Fixed() button = gtk.Button("Click") button.set_size_request(80, 35) self.id = button.connect("clicked", self.on_clicked) fixed.put(button, 30, 50) check = gtk.CheckButton("Connect") check.set_active(True) check.connect("clicked", self.toggle_blocking, button) fixed.put(check, 130, 50) self.connect("destroy", gtk.main_quit) self.add(fixed) self.show_all() def on_clicked(self, widget): print "clicked" def toggle_blocking(self, checkbox, button): if checkbox.get_active(): button.handler_unblock(self.id) else: button.handler_block(self.id) PyApp() gtk.main()
فى هذا المثال، لدينا زر وصندوق تحقق، اذا ضغطنا على الزر وكان صندوق التحقق منشط يتم طباعة كلمة clicked حيث يمنع/يتيح معالج الإشارة clicked
self.id = button.connect("clicked", self.on_clicked)الطريقة connect تعيد لنا معرف المعالج، اللذى قد نستخدمه فى اتاحته او منعه.
def toggle_blocking(self, checkbox, button): if checkbox.get_active(): button.handler_unblock(self.id) else: button.handler_block(self.id)
هذه الأسطر تمنع وتتيح معالجات الإشارات مع الطرق المناسبة
Figure: Blocking a callback
عملنا فى هذا الفصل على الإشارات.
Home Contents Top of Page