Home  Contents

Custom widget in GTK#



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

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

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



Burning widget

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

burning.cs

using Gtk;
using Cairo;
using System;
 
class Burning : DrawingArea
{

    string[] num = new string[] { "75", "150", "225", "300", 
        "375", "450", "525", "600", "675" };

    public Burning() : base()
    {
        SetSizeRequest(-1, 30);
    }

    protected override bool OnExposeEvent(Gdk.EventExpose args)
    {
        
        Cairo.Context cr = Gdk.CairoHelper.Create(args.Window);
        cr.LineWidth = 0.8;

        cr.SelectFontFace("Courier 10 Pitch", 
            FontSlant.Normal, FontWeight.Normal);
        cr.SetFontSize(11);

        int width = Allocation.Width;

        SharpApp parent = (SharpApp) GetAncestor (Gtk.Window.GType);        
        int cur_width = parent.CurValue;

        int step = (int) Math.Round(width / 10.0);

        int till = (int) ((width / 750.0) * cur_width);
        int full = (int) ((width / 750.0) * 700);

        if (cur_width >= 700) {
            
            cr.SetSourceRGB(1.0, 1.0, 0.72);
            cr.Rectangle(0, 0, full, 30);
            cr.Clip();
            cr.Paint();
            cr.ResetClip();
            
            cr.SetSourceRGB(1.0, 0.68, 0.68);
            cr.Rectangle(full, 0, till-full, 30);    
            cr.Clip();
            cr.Paint();
            cr.ResetClip();

        } else { 
             
            cr.SetSourceRGB(1.0, 1.0, 0.72);
            cr.Rectangle(0, 0, till, 30);
            cr.Clip();
            cr.Paint();
            cr.ResetClip();
       }  

       cr.SetSourceRGB(0.35, 0.31, 0.24);
       
       for (int i=1; i<=num.Length; i++) {
           
           cr.MoveTo(i*step, 0);
           cr.LineTo(i*step, 5);    
           cr.Stroke();
           
           TextExtents extents = cr.TextExtents(num[i-1]);
           cr.MoveTo(i*step-extents.Width/2, 15);
           cr.TextPath(num[i-1]);
           cr.Stroke();
       }
        
        ((IDisposable) cr.Target).Dispose();                                      
        ((IDisposable) cr).Dispose();

        return true;
    }
}


class SharpApp : Window {
 
    int cur_value = 0;
    Burning burning;
    
    public SharpApp() : base("Burning")
    {
        SetDefaultSize(350, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };
       
        VBox vbox = new VBox(false, 2);
        
        HScale scale = new HScale(0, 750, 1);
        scale.SetSizeRequest(160, 35);
        scale.ValueChanged += OnChanged;
        
        Fixed fix = new Fixed();
        fix.Put(scale, 50, 50);
        
        vbox.PackStart(fix);
        
        burning = new Burning();
        vbox.PackStart(burning, false, false, 0);

        Add(vbox);

        ShowAll();
    }
    
    void OnChanged(object sender, EventArgs args)
    {
        Scale scale = (Scale) sender;
        cur_value = (int) scale.Value;
        burning.QueueDraw();
    }
    
    public int CurValue {
        get { return cur_value; }
    }


    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

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



 string[] num = new string[] { "75", "150", "225", "300", 
     "375", "450", "525", "600", "675" };

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

 SharpApp parent = (SharpApp) GetAncestor (Gtk.Window.GType);        
 int cur_width = parent.CurValue;

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

 int till = (int) ((width / 750.0) * cur_width);
 int full = (int) ((width / 750.0) * 700);

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

 cr.SetSourceRGB(1.0, 1.0, 0.72);
 cr.Rectangle(0, 0, full, 30);
 cr.Clip();
 cr.Paint();
 cr.ResetClip();

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



 TextExtents extents = cr.TextExtents(num[i-1]);
 cr.MoveTo(i*step-extents.Width/2, 15);
 cr.TextPath(num[i-1]);
 cr.Stroke();

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

 void OnChanged(object sender, EventArgs args)
 {
     Scale scale = (Scale) sender;
     cur_value = (int) scale.Value;
     burning.QueueDraw();
 }

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

We get the value from the scale widget, store it in the cur_value variable for later use. We redraw the burning widget.


Burning widget

Figure: Burning widget

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


Home ‡ Contents ‡ Top of Page