Home  Contents

Custom widget in PyGTK

هل تسألت كيف تم تنفيذ عنصر ما من الواجهة فى تطبيق ما؟ غالبا كل من يريد ان يصبح مبرمجا فعل، ثم عند النظر لقائمة الويدجتس اللتى تقدمها لك مكتبتك الرسومية المفضلة، ولكن لاتجدها؟ ادوات تطوير التطبيقات بتقدملك اهم الويدجتس مثل الأزرار، ويدجات النصوص، المنزلقات،.. الخ ولكن لايوجد من يقدم لك كل شئ.

هناك نوعين من ادوات تطوير التطبيقات، سبارطية (مثل FLTK لاتقدم لك الا الأساسيات ليقوم المبرمج بإنشاء مايريده بنفسه) وثقيلة (مثل PyQt4 مع العديد من الويدجتس ولكنها ايضا لاتوفر لك كل شئ مثلا ويدجت لحرق اسطوانات؟ (مثل النيرو او k3B وغيرهم). وايضا ادوات فى الغالب لاتحتوى اداة تطوير التطبيقات على ال charts

لذيا يجب ان ينشئ المبرمجين هذه الويدجتس بأنفسهم، وذلك بإستخدام ادوات الرسم المتوفرة فى اداة التطوير.هنالك احتمالين تعديل وتحسين ويدجت موجود بالفعل، او انشاء واحد من الصفر



Burning widget

شبيه بما تراه فى Nero, K3B او غيرهم من برامج حرق الإسطوانات

burning.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example creates a burning
# custom widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk
import cairo

class Burning(gtk.DrawingArea):

    def __init__(self, parent):
        self.par = parent
        super(Burning, self).__init__()
 
        self.num = ( "75", "150", "225", "300", 
            "375", "450", "525", "600", "675" )
 
        self.set_size_request(-1, 30)
        self.connect("expose-event", self.expose)
    

    def expose(self, widget, event):
        cr = widget.window.cairo_create()
        cr.set_line_width(0.8)

        cr.select_font_face("Courier", 
            cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
        cr.set_font_size(11)

        width = self.allocation.width
     
        self.cur_width = self.par.get_cur_value()

        step = round(width / 10.0)

        till = (width / 750.0) * self.cur_width
        full = (width / 750.0) * 700

        if (self.cur_width >= 700):
            
            cr.set_source_rgb(1.0, 1.0, 0.72)
            cr.rectangle(0, 0, full, 30)
            cr.clip()
            cr.paint()
            cr.reset_clip()
            
            cr.set_source_rgb(1.0, 0.68, 0.68)
            cr.rectangle(full, 0, till-full, 30)
            cr.clip()
            cr.paint()
            cr.reset_clip()

        else:     
            cr.set_source_rgb(1.0, 1.0, 0.72)
            cr.rectangle(0, 0, till, 30)
            cr.clip()
            cr.paint()
            cr.reset_clip()
       

        cr.set_source_rgb(0.35, 0.31, 0.24)
        
        for i in range(1, len(self.num) + 1):
            cr.move_to(i*step, 0)
            cr.line_to(i*step, 5)
            cr.stroke()
            
            (x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1])
            cr.move_to(i*step-width/2, 15)
            cr.text_path(self.num[i-1])
            cr.stroke()
       
        
 
class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Burning")
        self.set_size_request(350, 200)        
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)

        self.cur_value = 0
       
        vbox = gtk.VBox(False, 2)
        
        scale = gtk.HScale()
        scale.set_range(0, 750)
        scale.set_digits(0)
        scale.set_size_request(160, 35)
        scale.set_value(self.cur_value)
        scale.connect("value-changed", self.on_changed)
                
        fix = gtk.Fixed()
        fix.put(scale, 50, 50)
        
        vbox.pack_start(fix)
        
        self.burning = Burning(self)
        vbox.pack_start(self.burning, False, False, 0)

        self.add(vbox)
        self.show_all()
        
        
    def on_changed(self, widget):
        self.cur_value = widget.get_value()
        self.burning.queue_draw()
    
    
    def get_cur_value(self):
        return self.cur_value
    

PyApp()
gtk.main()

نضع مساحة الرسم بالأسفل ونرسم الويدجت بالكامل يدويا.. كل الكود المهم يقع فى الطريقة expose الخاصة بويدجت الحرق.. هذا الويدجت يعرض المساحة الكلية للوسط مثلا ال CD ROM وايضا المساحة المتاحة فيه. ويتم التحكم فيه عن طريق مقياس scale.. القيمة الصغرى 0 والعظمى 750 وعند وصولنا لل 700 نرسم باللون الأحمر -لتشير ل overburning-





 self.num = ( "75", "150", "225", "300", 
     "375", "450", "525", "600", "675" )

هذه الأرقام ستعرض على ويدجت الحرق.. لعرض المساحة

 self.cur_width = self.par.get_cur_value()

هذان السطران للحصول على القيمة الحالية للمقياس -scale- ونحصل على الأب ومنه نحصل على القيمة الحالية..

 till = (width / 750.0) * self.cur_width
 full = (width / 750.0) * 700

المتغير till يحدد المساحة الكلية للرسم وتأتى قيمتها من المقياس -المنزلق او المسطرة- scale .. وهى النسبة للمساحة كلها. و المتغير full يحدد النقطة التى سنبدأ عندها الرسم باللون الأحمر

 cr.set_source_rgb(1.0, 1.0, 0.72)
 cr.rectangle(0, 0, till, 30)
 cr.clip()
 cr.paint()
 cr.reset_clip()

هذا الكود يرسم مستطيل اصفر حتى النقطة اللتى يمتلئ فيها ال CD

 (x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1])
 cr.move_to(i*step-width/2, 15)
 cr.text_path(self.num[i-1])
 cr.stroke()

هذا الكود يرسم الأرقام على ويدجت الحرق. ونحسب مقدار ال TextExtents لنموضع النص بطريقة سليمة



 def on_changed(self, widget):
     self.cur_value = widget.get_value()
     self.burning.queue_draw()

نحصل على القيمة من المقياس ونخزنها فى المتغير cur_value لإستخدام لاحق، ونرسم ويدجت الحرق


Burning widget

Figure: Burning widget

فى هذا الفصل انشأنا ويدجت من البداية


Home ‡ Contents ‡ Top of Page