Home Previous Up Next مكتبة GTK وبرنامج glade
حول
المحتويات
مشاريع
ثواب
مقالات
تنزيل
English

مكتبة GTK وبرنامج glade

محتويات هذا الفصل:

8.3.1 مقدمة

تعتبر مكتبة gtk أي Gimp tool kit من أقوى المكتبات لعمل برامج ذات واجهة رسومية وتفاعلية. نعم هي التي صمم gimp و كل برامج غنوم عليها وهي سهلة ومتوفرة لأكثر من نظام تشغيل منها لينكس و MacOS و ويندوز ولكن اصدار لينكس هو الأشهر والأنشط وهو الإصدار المركزي لها ، أما اصدار ويندوز فهو أقل نشاطاً وتوفراً ودعماً لكنه موجود. وبدأً من الإصدار الثاني كانت هذه المكتبة تدعم الكثير من اللغات ومنها اللغة العربية وتوفر الكثير من المزايا التي لا ينافسها فيها إلا مكتبة QT الخاصة ب KDE والفرق الأهم بين gtk و QT هو الرخصة فالأولى مرخصة وفقاً ل lgpl أي يمكنك استعمالها في عمل برامج تجارية أو مجانية أما QT فهي مجانية إذا عملت برامج مفتوحة و حرة وتجارية وعليك شراء رخصة إذا عملت برامج تجارية.

تتوفر مكتبة gtk في أكثر من لغة أهمها C/C++ وهناك perl و python و php بالنسبة ل php حتى الإصدار الرابع توفر gtk1 التي لا تدعم العربية وعليك الحصول على php 5 التي توفر gtk2 ويمكن الحصول عليها على كل CVS وتركيبها من المصدر تجد المزيد من التفاصيل على موقع www.gtk.org/bindings سنشرح كل شيء بلغة سي ثم نتحدث عن اللغات الأخرى ولا داعي أن أذكر أن perl و غيرها أسهل مليون مرة من لغة سي لذا يمكنك أن تبدأ بلغة perl أو python أو غيرهما ، أعرف أن لغة سي تشكل صدمة للجدد ولكنها اللغة المركزية ومنها يحول إلى اللغات الأخرى.

ومكتبة gtk هي تركيب من أكثر من مكتبة فهي بنيت فوق gdk أي gimp drawing kit للتعامل مع الرسم ومع مكتبة pango بدءاً من الإصدار الثاني ل gtk من أجل العالمية ودعم اللغات المختلفة مثل لغتنا العربية لذا عليك التعامل مع تلك المكتبات بين الحين والآخر

8.3.2 تعلم gtk

المرجع الأساسي يأتي مع حزمة تطوير gtk ويتم تركيبه في مجلد /usr/share/gtk-doc/ حيث تجد مجلد باسم html يحتوي مجلدات فرعية عن gtk وغيرها وهو مكان يحتوي على معلومات مفصلة تفصيلاً مملاً يكون مزعجا في البداية لكثرة التفصيل والمعلومات الدقيقة والمتشابكة ولكنه سيكون المكان الأفضل كمرجع ، أهم صفحة فيه هي Object Hierarchy التي توضح الخريطة الوراثية لكائنات gtk! في البداية ربما تحب أن تلقي نظرة على tutotial الموجود على موقع www.gtk.org/tutorial وهناك الكثير من الوثائق على موقع http://developer.gnome.org/doc من أهم الوثائق التي تهمنا كعرب وهي http://developer.gnome.org/dotplan/proting التي تتحدث عن كيفية تحويل البرامج من gtk1 التي لا تدعم العربية إلى gtk2 التي تدعم العربية ويمكنك تشغيل برنامج gtk-demo

قد تعتبر هذا غريباً بعض الشيء ولكن يمكنك تعلم gtk من ملفات headers أو من الملف المصدري ل gtk وطبعا هذا هو المكان الآخير ، ويمكن تعلمها من قراءة الملفات المصدرية للكثير من البرامج المفتوحة ومن الملفات المولدة بواسطة glade

8.3.3 كيف تكتب برنامج على gtk ؟

يمكنك استعمال برنامج مثل glade و glade2 لتوليد البرنامج وتصميمه باللغة التي تريد ،أي أنهما يكتبان البرنامج عنك ، ويقومان بترتيبه بحث يتم استعمال أدوات مثل auto-config ويتم وضع ملفات المصدر في مجلد src والملف الوحيد الذي عليك التعديل فيه هو ملف ال callbacks في حالة لغة C هو callbacks.c الذي يحتوي على وظائف تتبع الأحداث للتفاعل مع المستخدم ولتصنيف البرنامج كل ما عليك هو تنفيذ النص البرمجي autogen.sh (على ما أذكر!!) وأكثر من ذلك يمكنك تحميل ملف ال glade وتشغيله مباشرة دون أن تصنفه مثلاً هذا الكود بلغة السي يقوم بتحميل ملف اسمه filename.glade بعد تصنيف البرنامج (انظر الطريقة أدناه) قم بتصميم ملف على glade وخزنه باسم filename.glade ثم شغل برنامجنا الآن أغلقه وعدل التصميم ثم شغله مرة أخرى وانظر النتيجة

#include <gtk/gtk.h>
#include <glade/glade.h>

void some_handler(GtkWidget *widget) {
    /* a handler referenced by the glade file.  Must not be static
     * so that it appears in the global symbol table. */
}

int main(int argc, char **argv) {
    GladeXML *xml;
    GtkWidget *widget;

    gtk_init(&argc, &argv);
    xml = glade_xml_new("filename.glade", NULL, NULL);

    /* get a widget (useful if you want to change something) */
    widget = glade_xml_get_widget(xml, "widgetname");

    /* connect signal handlers */
    glade_xml_signal_autoconnect(xml);

    gtk_main();
    return 0;
}

ولكن تصميم برنامج مباشرة ليس صعباً ولن تكون بحاجة لتحديد حجم وموقع كل زر و كل جسم بالبيكسل ورسمها ، في مكتبة gtk نستخدم نظام تكديس packing يقوم على وضع الأجسام في حاويات وترتيبها وكأنها في جدول ونحدد الحد الأدنى لحجمها إذا أردنا ونحدد فيما إذا كنا نريد أن تكبر وتصغر عند تحجيمها أم تبقى كما هي ويتغير الهامش وهكذا نكون حصلنا على التصميم الذي نريد

8.3.4 تصنيف البرنامج compiling

لتصنيف برنامج مكتوب على gtk عليك تحديد أسماء المجلدات التي تحتوي ملفات headers ذات الإمتداد h وأيضاً ربط برنامجك بمكتبة gtk أي ملفات ذات الإمتداد a اذا كنت تستعمل gcc فإليك الخيارات التي يجب أن تمررها له لمكتبة gtk2

-I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/pango-1.0 -I/usr/X11R6/include -I/usr/include/freetype2 -I/usr/include/atk-1.0

-L/usr/lib -L/usr/X11R6/lib -lgtk-x11-2.0 -lgdk-x11-2.0 -lXi -lgdk_pixbuf-2.0 -lm -lpangox -lpangoxft -lXft -lXrender -lXext -lX11 -lfreetype -lpango -latk -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0

ويمكن أن تختلف المجلدات من توزيعة لأخرى وأيضا تختلف من اصدار gtk إلى آخر مثلاً في gtk1 هناك القليل من المكتبات الإضافية فهي لا تعتمد على pango وغيرها مما يجعل تصنيف البرمج مزعجاً ، ولكن لا تظن أنك يجب أن تعرف شيء عن هذه الطلاسم كل ما عليك هو استدعاء الأداة pkg-config وأخذ ناتج تنفيذها ، التي حلت مكان أداة gtk-config القديمة التي كانت تستعمل في gtk1

# the old method الطريقة القديمة
bash$ gcc myfile.c -o myfile `gtk-config --cflags` `gtk-config --libs`
# the new method الطريقة الحديثة
bash$ gcc myfile.c -o myfile  `pkg-config --cflags --libs gtk+-2.0`

8.3.5 البداية

برنامج gtk العادي يبدو مثل هذا

/* البداية التقليدية */
#include <gtk/gtk.h>

int main(int argc, char *argv[])
{
/* نعرف متغيرات تمثل النافذة والأزرار */
GtkWidget *win, *btn;
/* نقوم بالعمليات الإستهلالية */
gtk_init(&argc, &argv);

/* نبدأ برسم النوافذ والأزرار */
/* نحجز نافذة جديدة */
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* نحجز زر جديد */
btn = gtk_button_new_with_label("Hello World !!");
/* نضع الزر في النافذة */
gtk_container_add (GTK_CONTAINER (win), btn);
/* نحدد حجم النافذة الإبتدائي */
gtk_window_set_default_size(GTK_WINDOW(win), 200, 200);

/* نحدد وظائف التفاعل وتتبع الأحداث */
/* مثلاُ نربط حدث إغلاق النافذة بالخروج */
g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(gtk_main_quit), NULL);

/* نظهر النافذة ومحتوياتها */
gtk_widget_show_all(win);

/* النهاية التقليدية */
/*
	تبقي البرنامج عاملاً وتتبع الأحداث
	إلى أن يتم إغلاق البرنامج
*/
gtk_main();
return 0;
}

هذا البرنامج عبارة عن نافذة تحتوي زر اسمه btn مكتوب عليه Hello World عند النقر على زر الإغلاق من مدير النوافذ يتم استدعاء الوظيفة gtk_main_quit الموجودة ضمن مكتبة gtk والتي تقوم بإغلاق البرنامج والخروج ، أما الزر btn فإن النقر عليه لا يقوم بشيء لربط وظيفة معينة به
g_signal_connect(G_OBJECT(win), "clicked", G_CALLBACK(gtk_main_quit), NULL); ويمكن وضع أي وظيفة للقيام بها كرد على ضغط الزر وتكون صيغتها أنها تأخذ المعامل الأول هو مؤشر على الزر نفسه ويكون من نوع GtkWidget* والأخير من نوع gpointer * حيث يكون مؤشراً على بيانات اضافية يتم تمريرها له بدلاً من NULL المعامل الأخير في g_signal_connect ويمكن أن يأخذ معاملات أخرى بينهما قد تمثل مكان حدوث النقر أو النص الذي أضيف ... هذا يعتمد على صنف الكائن وتجدها مفصلة في مرجع gtk الذي تحدثنا عنه.

في الإصدارات السابقة من gtk ماقبل gtk2 استعمل gtk_signal_connect مكان g_signal_connect كما في المثالين

gtk_signal_connect(GTK_OBJECT(win),"destroy", GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
gtk_signal_connect(GTK_OBJECT(win),"clicked", win->destroy(),NULL);
ولكن يجب أن لا تستعملها في البرامج الحديثة لأنها موجودة للتوافق مع gtk1 فقط.

إذا كنت تريد استدعاء التحديث أثناء قيامك بعمليات معقدة وتأخذ وقتاً حتى لا يبدو برنامج متوقف عن الإستجابة ضع هذا السطر وسط تلك الحسابات

	/* ... */
 while(gtk_events_pendings()) gtk_main_iteration();
	/* ... */

8.3.6 أسماء الوظائف و الثوابت والصنوف الأساسية

أسماء الوظائف في gtk هي عبارة عن سلسلة تفصل بين مقاطعها شرطة تحتية "_" تبدأ باسم المكتبة مثل gtk و gdk ... إلخ ثم يأتي الصنف -إن وجد- مثل button أو window ثم الوظيفة مثل new فتصبح مثلاً gtk_button_new وأول المعاملات التي يأخذها يكون في الغالب مؤشر على الكائن الذي نريد تطبيق الوظيفة عليه مثلاً gtk_window_set_title((GtkWindow*)win,"The brand new title"); لاحظ أن وظائف حجز كائن جديد تعيد مؤشراً لكائن من نوع GtkWidget وتأخذ معظم وظائف تعديل خصائصها هذا النوع من المعاملات أي مؤشر إلى نوع GtkWidget أو نوع الكائن الذي تعود له هذه الصفة كما لاحظنا gtk_window_set_title تأخذ مؤشر إلى GtkWindow . لقد كانت وظائف الكائنات في الإصدارة الأولى تأخذ معاملاتها من نفس نوعها مثل GtkButton للأزرار وليس من نوع GtkWidget مما يوجب عليك القيام دائماً بالتحويل إما بالطريقة التقليدية (GtkButton*)btn1 أو بالإختصار/الوظيفة المناسبة GTK_BUTTON(btn1) ولكن في الإصدار الثانية من Gtk فقط عليك التحويل في حالات نادرة لها علاقة بالنوافذ والحاويات أما أغلب الوظائف تأخذ GtkWidget. على أي حال إذا لم تقم بالتحويل فإن أكثر ما يمكن أن تحصل عليه هو تنبيه warning ولا يشكل خطأ.

أما أنواع المتغيرات وأسماء الصنوف فهي تكون بأحرف استهلالية كبيرة ودون فاصل ، اسم المكتبة ثم النوع مثل GtkButton وكل تعاملاتنا تكون بمؤشرات ، أضف إلى ذلك ما قلناه عن أننا في الغالب سنستعمل فقط GtkWidget الثوابت والإختصارات تكون بأحرف كبيرة ويفصل بين مقاطعها "_" مثل GTK_WINDOW_TOPLEVEL

8.3.7 التصميم باستعمال الصناديق الأفقية والعامودية

بعد حجز نافذة يمكنك تحديد حجمها gtk_window_set_default_size(GTK_WINDOW(win), 600, 400); وعنوانها gtk_window_set_title(GTK_WINDOW(win),"My Title"); ثم نقسم النافذة إلى صفوف ونضع في الصف الأول القوائم ثم في الآخر سطر الأدوات والذي يليه ربما نقسمه إلى عدة أعمدة نضع فيها مثلاً شريطاً جانبياً قابلاً للتحجيم مع مساحة للنص وصف جديد يحتوي بعض الأزرار وسطر آخر يحتوي سطر الحالة إذا كنت تفكر لتصميم برنامجك بهذه الطريقة فتطبيق ذلك لا يحتاج أي احداثيات وطلاسم كل ما عليك هو استعمال GtkVBox و GtkHBox حيث V و H ترمز للعامودي والأفقي على الترتيب

vbox1=gtk_vbox_new(FALSE,3); تقوم بعمل صندوق لوضع الصفوف فيه بحيث لا تكون هذه الصناديق متجانسة ، إذا وضعنا TRUE مكان FALSE يصبح متجانس أي كل الصفوف بنفس الحجم والرقم ثلاثة يشير إلى عرض الخط الفاصل. بعد ذلك نضيفه إلى النافذة gtk_container_add(GTK_CONTIANER(win),vbox1); ثم نبدأ بإضافة الكائنات (الصفوف) في مثالنا نريد سطر القوائم جديد menubar1 = gtk_menu_bar_new(); ثم نضيفه على شكل صف في الصندوق gtk_box_pack_start(GTK_BOX(vbox1),menubar1, FALSE, FALSE,0); حيث ال FALSE هي أننا لا نريده أن يكبر عند تكبير النافذة والثانية أنه عند تصغيره يتم إخفاء جزء منه وليس تصغير حجمه على الترتيب. أما الصفر فهي الهامش. الوظيفة gtk_box_pack_start تضيف الكائنات من البداية إلى النهاية في مثالنا من فوق لتحت إذا أردت أن تعكس العملية استعمل gtk_box_pack_end بنفس المعاملات. ويمكنك ايضاً اضافتها باستعمال gtk_box_pack_start_defaults(GTK_BOX(vbox1),menubar1); أو حتى الطريقة الأولى لإضافة العناصر وهي gtk_container_add(GTK_BOX(vbox1),menubar1); ولأنهما تأخذان معاملين فقط فإنك لن تستطيع تحديد طريقة التكديس وسيتم استخدام التلقائية.

لعمل قائمة ملف مثلاً نحجزه هكذا filemenu=gtk_menu_item_new_with_label("File"); ثم نضيفه إلى سطر القوائم بالطريقة المعتادة gtk_container_add(GTK_CONTIANER(menubar1),filemenu); لنضيف خيار جديد إلى قائمة ملف نحجر newmenu=gtk_menu_item_new_with_label("new"); ثم نضيف gtk_container_add(GTK_CONTIANER(filemenu),newmenu); ولنفرض أننا نريد قائمة جديد أن تتفرع إلى قائمة بها اختياران مثلاً نافذة جديدة و ملف جديد نحجزها ب newwinmenu=gtk_menu_item_new_with_label("new window"); و newfilemenu=gtk_menu_item_new_with_label("new file"); ونضيفها لقائمة "جديد" ب gtk_container_add(GTK_CONTIANER(newmenu),newwinmenu); و gtk_container_add(GTK_CONTIANER(newmenu),newfilemenu);

في الصف التالي نريد إضافة عمودين الثاني مكان لتحرير النص والأول فارغ ربما للاستخدامات المستقبلية سنضع فيه نص ثابت مكتوب عليه قريباً soon نقوم بحجز صندوق يحتويها ب hbox1=gtk_hbox_new(FALSE,3); ونضيفه إلى الصفوف gtk_box_pack_start(GTK_BOX(vbox1),hbox1, TRUE, FALSE,0); الآن لكي نضيف العامود الأول وهو عبارة عن نص من سطر واحد نحجزه أولاً entry1=gtk_entry_new(); ثم نضيفه gtk_box_pack_start(GTK_BOX(hbox1),entry1, TRUE, FALSE,0); ونكتب فيه كلمة soon gtk_entry_set_text("soon!"); ولأننا لا نريد أن تكون هذه للإدخال بل نص ثابت gtk_editable_set_editable(entry1,FALSE); ثم نضيف العامود الثاني الذي يحتوي على مكان لتحرير نص متعدد الأسطر text1=gtk_text_view_new(); ثم اضافته بعد حجزه gtk_box_pack_start(GTK_BOX(hbox1),text1, TRUE, FALSE,0); وهو ليس لعرض النص كما قد يخطر ببالك فقط بل يمكن استخدامه لتحرير النص وذلك بتغير الخاصية "editble" إلى TRUE وذلك باستدعاء gtk_text_view_set_editable(text1,TRUE); وأيضاً يمكن استخدامه ليس فقط لتحرير النصوص العادية بل وأيضاً التي تحتوي على ألوان وخصائص مختلفة بل وأيضا صور مدرجة وروابط و... الكثير من الأشياء التي يمكنك أن تفكر فيها.

ولأن منطقة تحرير النص هي الكائن الأساسي نقوم بإعطائها حجم كبير نسبياً بل ونجعله الحد الأدنى للحجم (أي يمكن أن يزيد عنه ولكن لا يجوز أن يقل عنه ) وذلك باستدعاء gtk_widget_set_size_request(text1,400,400); ولا تستخدم الطريقة القديمة gtk_widget_set_usize(text1,400,400); فهي موجودة فقط للتوافق مع الإصدارات القديمة فقط.

نتابع إضافة سطر (صندوق أفقي) يحتوي بعض الأزرار hbox2=gtk_hbox_new(TRUE,3); نحجز زرين بـ btn1=gtk_button_new_with_label("OK"); و btn2=gtk_button_new_with_label("Clear"); ثم نضيفهما بـ gtk_box_pack_start(GTK_BOX(hbox2),btn1, FALSE, FALSE,0); و gtk_box_pack_start(GTK_BOX(hbox2),btn2, FALSE, FALSE,0);

وفي النهاية نضيف الصندوق الكبير الذي يحتوي كل شيء vbox1 إلى النافذة gtk_container_add(GTK_CONTIANER(win),vbox1); ونظهر النافذة وما فيها gtk_widget_show_all(win);

 تلميح

يفترض أن تحدد أنك تريد اظهار الكائن ب gtk_widget_show(my_widget_name); لكل الكائنات في النافذة ولكن هذا سيكون مملاً الأجدى من ذلك أن تستعمل gtk_widget_show_all(my_window_name); لإظهار النافذة وكل شيء داخلها

سنحصل من البرنامج على ما نريد غير أن الحاجز الذي يفصل بين منطقة تحرير النص وصندوق soon لا يمكن تحريكه فإذا أردناه أن يتحرك نستبدل الصندوق الأفقي hbox1 ب hpaned وذلك باستعمال hpaned1=gtk_hpaned_new(); وهو كائن له ولدين يفصل بينهما حاجز متحرك يمكن جره ويكون ذلك بوضع الكود التالي

/* ... */
hpaned=gtk_hpaned_new();
gtk_box_pack_start(GTK_BOX(vbox1),hpaned1, TRUE, FALSE,0);
gtk_container_set_border_width(GTK_CONTAINER(hpaned1),3);
entry1=gtk_entry_new();
gtk_paned_pack1(GTK_PANED(hpaned1),entry1, TRUE,TRUE);
gtk_entry_set_text("soon!");
gtk_editable_set_editable(entry1,FALSE);
text1=gtk_text_view_new();
gtk_paned_pack2(GTK_PANED(hpaned1),text1, TRUE,TRUE);
gtk_text_view_set_editable(text1,TRUE);
/* ... */
مكان الكود القديم التالي
/* ... */
hbox1=gtk_hbox_new(FALSE,3);
gtk_box_pack_start(GTK_BOX(vbox1),hbox1, TRUE, FALSE,0);
entry1=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox1),entry1, TRUE, FALSE,0);
gtk_entry_set_text("soon!");
gtk_editable_set_editable(entry1,FALSE);
text1=gtk_text_view_new();
gtk_box_pack_start(GTK_BOX(hbox1),text1, TRUE, FALSE,0);
gtk_text_view_set_editable(text1,TRUE);
/* ... */
لاحظ أننا استعملنا gtk_paned_pack1 لإضافة الإين الأول و gtk_paned_pack2 الأول سيظهر على اليسار والثاني على اليمين إذا كانت اللغة الإنجليزية هي لغة النظام أما إذا كانت العربية فيكون الأول على اليمين .
 تلميح

بدء من الإصدار الثاني ل gtk فهي تدعم العربية بشكل ممتاز بسبب pango لهذا ليس عليك أن تقلق أو تغير في حساباتك اكتب البرنامج وكأنه إنجليزية وعند اختيار العربية سترى برنامجك وقد أصبحت قوائمه من اليمين وتغير ترتيب الأشياء لتصبح من اليمين لليسار لا داعي لإعادة تصميم البرنامج. وأكثر من ذلك فهي تدعم اللغات التي تكتب من فوق إلى تحت ومن اليمين إلى اليسار و التي تكتب من فوق إلى تحت ومن اليسار إلى اليمين

يمكن تغيير خصائص أي كان من خلال الوظيفة g_object_set_property ومعرفة قيمتها بالوظيفة g_object_get_property هاتان الوظيفتان تأخذان 3 معاملات هي مؤشر للكائن من نوع GObject وسلسلة نصية اسم الخاصية مثلاً "editable" أو "font" وأخيراً مؤشر من نوع GValue وهو يمثل القيمة.
/* I'm not sure if it works or correct */
GValue v;
g_value_init(&v,G_TYPE_STRING);
g_value_set_instance(&v,"monospace 10");
g_object_set_property((GObject*)entry1,"font",&v);

8.3.8 بعض التطبيقات

أول تطبيق سنصممه هو عبارة عن برنامج بسيط يأخذ رقمين ويجمعهما شكل البرنامج عبارة عن ثلاث حقول لإدخال رقمي يقابلها عناوينها التي هي First Number و Second Number و Sum موضوعة في ثلاث صفوف بشكل عامودي فوق بعضها البعض ، يأتي تحتها زر OK. إليكم نص البرنامج:

/* البداية التقليدية */
#include <stdio.h> /* من أجل sprintf */
#include <stdlib.h> /* للمستقبل */
#include <math.h> /* للمستقبل */
#include <gtk/gtk.h>

/* نعرف متغيرات تمثل النافذة والأزرار */
GtkWidget *win, *btn1;
GtkWidget *vbox1,*hbox1,*hbox2,*hbox3,*hbox4;
GtkWidget *label1,*label2,*label3;
GtkWidget *entry1,*entry2,*entry3;

/* نخبر سي عن نموذج الوظيفة */
void calc_result(GtkButton *btn,gpointer *ptr);

int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
/* نحجز الكائنات */
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title((GtkWindow*)win,"Sum");
vbox1 = gtk_vbox_new(TRUE,3);
hbox1 = gtk_hbox_new(FALSE,3); hbox2 = gtk_hbox_new(FALSE,3);
hbox3 = gtk_hbox_new(FALSE,3); hbox4 = gtk_hbox_new(FALSE,3);
label1 = gtk_label_new("First number:");
label2 = gtk_label_new("Second number:");
label3 = gtk_label_new("Sum :");
entry1 = gtk_entry_new();
entry2 = gtk_entry_new();
entry3 = gtk_entry_new(); /* الثالث يمكن أن يكون label */
btn1 = gtk_button_new_from_stock(GTK_STOCK_OK);
/* نضع كل واحد في مكانه  */
gtk_container_add (GTK_CONTAINER(win), vbox1);
gtk_container_add (GTK_CONTAINER(vbox1), hbox1);
gtk_container_add (GTK_CONTAINER(vbox1), hbox2);
gtk_container_add (GTK_CONTAINER(vbox1), hbox3);
gtk_container_add (GTK_CONTAINER(vbox1), hbox4);
gtk_container_add (GTK_CONTAINER(hbox1), label1); gtk_container_add (GTK_CONTAINER(hbox1), entry1);
gtk_container_add (GTK_CONTAINER(hbox2), label2); gtk_container_add (GTK_CONTAINER(hbox2), entry2);
gtk_container_add (GTK_CONTAINER(hbox3), label3); gtk_container_add (GTK_CONTAINER(hbox3), entry3);
gtk_container_add (GTK_CONTAINER(hbox4), btn1);
/* نحدد بعض خصائص الكائنات */
gtk_editable_set_editable(GTK_EDITABLE(entry1),TRUE);
gtk_editable_set_editable(GTK_EDITABLE(entry2),TRUE);
gtk_editable_set_editable(GTK_EDITABLE(entry3),FALSE);
/* نحدد وظائف التفاعل وتتبع الأحداث */
g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(btn1), "clicked", G_CALLBACK(calc_result), NULL);
/* نظهر النافذة ومحتوياتها */
gtk_widget_show_all(win);
/* النهاية التقليدية */
gtk_main();
return 0;
}
/* الوظيفة التي ينفذها عند نقر OK */
void calc_result(GtkButton *btn,gpointer *ptr) {
	const char *str1,*str2;
	char str3[40];
	float n1,n2,r;
/* هنا نأخذ السلسلة النصية التي تمثل الرقم */
	str1=gtk_entry_get_text(GTK_ENTRY(entry1));
	str2=gtk_entry_get_text(GTK_ENTRY(entry2));
/* هنا نحول من سلسلة نصية إلى رقم نسبي */
	n1=atof(str1); n2=atof(str2); 
	r=n1+n2;/* هنا نحسب */
	sprintf(str3,"%g",r); /*نحول إلى سلسلة نصية*/
/*
	يمكن استخدام ftoa(r);
	ولكني أفضل sprintf
	لأنني أتحكم في الصيغة
*/
/* نكتبها في خانة النتيجة */
	gtk_entry_set_text(GTK_ENTRY(entry3),str3);
	return TRUE;
}

نص البرنامج واضح ولا يحتاج إلى الكثير من الشرح، حجزنا صندوق عامودي ووضعنا فيه كل شيء حجزنا أربع صناديق أفقية ووضعنا في أول ثلاث عنوان ونص وفي الرابع وضعنا زر وعلى عكس ما هو متوقع لم أستخدم gtk_button_new_with_label("OK"); لعمل زر موافق، بل استخدمت gtk_button_new_from_stock(GTK_STOCK_OK); لأن هناك زر جاهز (وليس تفصيل) في مخازن Gtk2 وهي محلات عريقة! تحتوي على الكثير من الأزرار والقوائم الجاهزة والتي تملك صور معبرة وأيضا مترجمة لعدة لغات منها العربية (أي أنك توفر وقت الترجمة ووقت تصميم الأيقونة). وهناك الكثير منها يمكنك أن تراها بتنفيذ gtk-demo هناك ستجد قائمة طويلة بها وهي أيضا موجودة في المرجع. ويمكن استخدام طريقة مماثلة لعمل القوائم مثلاً gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN,NULL);

Simple GTK program

إن صنف GtkLabel يوفر كائن لعرض نص يمكن تغيير هذا النص فيما بعد بواسطة gtk_label_set_text(mylabel,str) حيث str هو السلسلة النصية، هذا الكائن مرن جداً، إذ يمكن أن تستخدم لعرض نص من أكثر من سطر أو حتى نص مرقوم markup (ملوّن أو بأكثر من حجم أو خط) وذلك بواسطة gtk_label_set_markup(mylabel,str) حيث str هو سلسلة نصية تحتوي راقمات tags تشبه تلك في HTML تسمى Pango makrup مثلاً

gtk_label_set_markup(mylabel,"I'm <big>NOT</big> kidding, e=mc<sup>2</sup>");
الراقمات المتوفرة هي b للخط السميك، و i للمائل، و u لمسطّر، و s يتوسطه خط (مشطوب) sub للنص المنخفض و sup للمرتفع، و big لتكبير الخط عمّا كان عليه، و small لتصغيره، و tt لخط Monospace المستخدم في الكود، وأخيراً الراقمة الأكثر استعمالاً span ولها السمات التالية:
السمةقيمتها
font_desc سلسلة تصف الخط مثل Sans Italic 12
font_family أو face عائلة الخط
size الخط مقاساً بعدد الأجزاء من 1000 من النقطة point
يمكن أن استعمال الحجوم المطلقة 'xx-small' و 'x-small' و 'small' و 'medium' و 'large' و 'x-large' و 'xx-large'
أو النسبية مثل 'smaller' و 'larger'.
style واحدة من 'normal' أو 'oblique' أو 'italic'.
weight سماكة الخط كرقم أو واحدة من 'ultralight' أو 'light' أو 'normal' أو 'bold' أو 'ultrabold' أو 'heavy'.
variant إما 'normal' أو 'smallcaps'.
stretch واحدة من 'ultracondensed' أو 'extracondensed' أو 'condensed' أو 'semicondensed' أو 'normal' أو 'semiexpanded' أو 'expanded' أو 'extraexpanded' أو 'ultraexpanded'.
foreground لون الخط رقماً مثل '#0000FF' أو اسماً مثل 'blue'.
background كما السابقة ولكن تحدد لون الخلفية
underline واحدة من 'single' أو 'double' أو 'low' أو 'none'.
rise صعود النص بالأجزاء من 10000 جزء من ارتفاع M.
strikethrough إما'true' أو 'false'.
lang رمز اللغة

الجزء الذي يمكن أن تراه أكثر تعقيداً هو calc_result الذي يحتوي على الكثير من الغموض. لاحظ أنني لم أحجز str1 و str2 والسبب أن gtk_entry_get_text تقوم بحجز المساحة ويجب أن لا تقوم بتحريرها أو التعديل عليها ولهذا كانت ثابتة const وهذه قاعدة عامة

 تحذير

وظيفة gtk التي تعيد متغير ثابت const يجب أن لا تحرره ب g_free(my_ptr); كما يفترض أن لا تكون قد حجزته وأعطيته قيمة بل تتركه NULL حتى تضع الوظيفة فيه القيمة المناسبة لأن هذه القيمة قد تكون داخلية. أما الوظائف التي تعيد مؤشرات ليست ثابتة const فإنه يجوز لك تحريرها متى شئت باستعمال g_free(my_ptr); من الأمثلة عليها gtk_something_new();

أما str3 فحجزت له 40 بايت - وأظنها كافية - لأنه يمرر ل sprintf التي لا تحجز ذاكرة. أما إذا كنت تتسائل عن سبب أخذي للمتغيرات على شكل سلسلة نصية ثم تحويلها لرقم ثم جمعها ثم إعادتها على كل سلسلة مرة أخرى وذلك لأن قيمة GtkEntry عبارة عن سلسلة نصية لكي نقوم بالحسابات علينا أن نحولها لرقم وبعد أن نقوم بالحسابات ولكي نظهر النتيجة في entry3 يجب أن تكون نص فنحولها مرة أخرى إلى نص

البرنامج التالي عبارة عن ساعة ايقاف أي نافذة بثلاث أزرار واحدة لبدء العد والآخر لإيقاف العد والأخير لتصفير الساعة. يتم إضهار الثواني في صندوق نصي GtkEntry لايسمح بالكتابة فيه.

/*
 * stopwatch2.c: A stopwatch with Gtk+2
 *
 * by Moayyad Al-Sadi<alsadi[at]gmail.com>
 * released under the terms of the GNU General Public License
 * visit www.gnu.org/copyleft
 */
#include <glib.h>
#include <gtk/gtk.h>
/* Public variables */
	GTimer *timer1;
	GtkWidget *win, *vbox1,*hbox1;
	GtkWidget *label1;
	GtkWidget *timer, *stopbtn,*startbtn,*resetbtn;
	gchar str[100]; double oldt=-1.0,newt=0.0;
/* idle function to update timer */
gint update_timer(gpointer ptr) {
	g_ascii_formatd(str,99,"%29.3f",newt=g_timer_elapsed(timer1,NULL));
	if (oldt!=newt)
		gtk_entry_set_text(GTK_ENTRY (timer),str);
	oldt=newt;
}
/* handlers for click the 3 buttons */
void start_event() {
	g_timer_start(timer1);
	update_timer(NULL);
}
void stop_event() {
	g_timer_stop(timer1);
	update_timer(NULL);
}
void reset_event() {
	g_timer_reset(timer1);
	g_timer_stop(timer1);
	update_timer(NULL);
}

int main(int argc, char *argv[]) {
	/* create the timer and put it on 0.0 */
	timer1=g_timer_new();
	g_timer_reset(timer1);
	g_timer_stop(timer1);
	
	gtk_init(&argc, &argv);
	/* Build the gui */
	win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	vbox1 = gtk_vbox_new(FALSE,3); /* homo,spacing */
	label1=gtk_label_new("Moayyad al-Sadi Stopwatch");
	timer=gtk_entry_new();
	hbox1 = gtk_hbox_new(TRUE,3);
	startbtn=gtk_button_new_with_label("start");
	stopbtn=gtk_button_new_with_label("stop");
	resetbtn=gtk_button_new_with_label("reset");
	/* add each widget to it parent */
	gtk_container_add(GTK_CONTAINER (win),vbox1);
	gtk_box_pack_start(GTK_BOX(vbox1),label1,	FALSE, FALSE,0); /* resize=shrink=false */
	gtk_box_pack_start(GTK_BOX(vbox1),timer,	FALSE, FALSE,0);
	gtk_box_pack_start(GTK_BOX(vbox1),hbox1,	TRUE, FALSE,0);
	gtk_box_pack_start(GTK_BOX(hbox1),startbtn,	TRUE, FALSE,0);
	gtk_box_pack_start(GTK_BOX(hbox1),stopbtn,	TRUE, FALSE,0);
	gtk_box_pack_start(GTK_BOX(hbox1),resetbtn,	TRUE, FALSE,0);
	/* set some properties */
	 /* gtk_window_set_default_size(GTK_WINDOW(win), 300, 300); */
	gtk_window_set_title(GTK_WINDOW(win),"Moayyad Stopwatch");
	gtk_editable_set_editable(GTK_EDITABLE(timer),FALSE);
	/* connect events */
	g_signal_connect(G_OBJECT(win),"destroy",gtk_main_quit,NULL);
	g_signal_connect(G_OBJECT(startbtn),"clicked", start_event,NULL);
	g_signal_connect(G_OBJECT(stopbtn),"clicked", stop_event,NULL);
	g_signal_connect(G_OBJECT(resetbtn),"clicked", reset_event,NULL);
	gtk_idle_add(update_timer,NULL);
	/* show all and wait to exit */
	gtk_widget_show_all(win);
	gtk_main();
	return 0;
}                                                                                                                             
		

لتصنيف البرنامج في Gtk1 يجب تعديل بعض الأسطر كما يلي

/* ... */
/* in main(...) */
	gtk_signal_connect(GTK_OBJECT(win),"destroy", GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
	gtk_signal_connect(GTK_OBJECT(startbtn),"clicked", GTK_SIGNAL_FUNC(start_event),NULL);
	gtk_signal_connect(GTK_OBJECT(stopbtn),"clicked", GTK_SIGNAL_FUNC(stop_event),NULL);
	gtk_signal_connect(GTK_OBJECT(resetbtn),"clicked", GTK_SIGNAL_FUNC(reset_event),NULL);
/* ... */
		

لاحظ استعمال الوظيفة gtk_idle_add والتي تعمل على استدعاء الوظيفة التي تحددها له بشكل متكرر عندما لا يقوم البرنامج بعمل أي شيء (أي أن يكون في وضع التوقف بانتظار حدث معين) تعيد هذه الوظيفة رقم يمكن تمريره إلى gtk_idle_remove لإيقاف تنفيذ تلك الوظيفة. وظيفة idle هذه تنفذ بشكل متكرر في فترات غير محددة في المقابل توجد الوظيفة gtk_timeout_add التي تمكنك من تحديد الفترات الزمنية بين استدعاءات المتكررة للوظيفة التي تحددها. يمكن تركيب حجم النافذة التي ستظهر باستعمال gtk_window_set_resizable(GTK_WINDOW(win),FALSE); ليبدو البرنامج منطقياً فلا يمكن تغير حجم النافذة.

البرنامج التالي عبارة عن محرر نصوص بسيط بقائمة وسطر أدوات toolbar يستتخدم GtkTextView وهو كائن ظهر في GTK 2 ولم يكن موجوداً في الإصدارات السابقة.

/*
 * gtk-ez-edit.c: A trival Gtk+2 Text editor
 *
 * by Moayyad Al-Sadi<alsadi[at]gmail.com>
 * released under the terms of the GNU General Public License
 * visit www.gnu.org/copyleft
 */
#include <glib.h>
#include <gtk/gtk.h>
/* Public variables */
    gchar*	filename;
    GtkWidget	*win, *vbox,*toolbar
    GtkWidget	*sw, *txt;
    GtkTextBuffer *buffer;
    GtkItemFactory	item_factory;
/* call backs prototypes */
void new_cb(gpointer data);
void open_cb(gpointer data);
void save_cb(gpointer data);
void save_as_cb(gpointer data);
void about_cb(gpointer data);
/* Main menu factory */
    GtkItemFactoryEntry menu_items[]={
    {"/_File",		NULL,		NULL,		0, "<Branch>",	0},
    {"/File/tearoff1",	NULL,		NULL,		0, "<Tearoff>",	0},
    {"/File/_New",	"<control>N",	new_cb,		0, "<StockItem>", GTK_STOCK_NEW},
    {"/File/_Open",	"<control>O",	open_cb,	0, "<StockItem>", GTK_STOCK_OPEN},
    {"/File/_Save",	"<control>S",	save_cb,	0, "<StockItem>", GTK_STOCK_SAVE},
    {"/File/Save _As",	"<control>A",	save_as_cb,	0, "<StockItem>", GTK_STOCK_SAVE_AS},
    {"/File/sep1",	NULL,		NULL,		0, "<Separator>",0},
    {"/File/_Quit",	"<control>Q",	gtk_main_quit,	0, "<StockItem>", GTK_STOCK_QUIT},
    {"/_Help",		NULL,		NULL,		0, "<Branch>",0},
    {"/Help/_About",	NULL,		about_cb,	0, NULL,0}
    }
int main(int argc, char *argv[]) {
    gtk_init(&argc, &argv);
    /* Build the GUI */
    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(win),"GTK+ Easy Text Editor");
    g_signal_connect(G_OBJECT(win),"destroy",gtk_main_quit,NULL);
    vbox = gtk_vbox_new(FALSE,3); /* homo,spacing */
    gtk_container_add(GTK_CONTAINER (win),vbox);

    item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", NULL);
    gtk_item_factory_create_items(item_factory,menu_items_number,menu_items, NULL);
    gtk_box_pack_start(GTK_BOX(vbox), item_factory_get_widget(item_factory,"<main>"),
	FALSE, FALSE,0); /* resize=shrink=false */
    toolbar = gtk_toolbar_new();
    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE,0);
    sw=gtk_scrolled_window(NULL,NULL);
    gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE,0);
    txt = gtk_text_view_new();
    buffer=gtk_text_view_get_buffer(txt);
    gtk_container_add(GTK_CONTAINER (sw),txt);
    
    gtk_toolbar_set_icon_size(toolbar,GTK_ICON_SIZE_SMALL_TOOLBAR);
    gtk_toolbar_set_style(toolbar,GTK_TOOLBAR_ICONS);
    gtk_toolbar_set_tooltips(toolbar,TRUE);
    gtk_toolbar_insert_stock(toolbar,GTK_STOCK_NEW,"create new document",
        NULL,new_cb,NULL,-1);
    gtk_toolbar_insert_stock(toolbar,GTK_STOCK_OPEN,"open a file",
        NULL,open_cb,NULL,-1);
    gtk_toolbar_insert_stock(toolbar,GTK_STOCK_SAVE,"save the file",
        NULL,save_cb,NULL,-1);
    gtk_toolbar_insert_stock(toolbar,GTK_STOCK_SAVE_AS,"save the file as other name",
        NULL,save_as_cb,NULL,-1);
}
void new_cb(gpointer data) {
    gtk_text_buffer_set_text(buffer,"",-1);
}
void update_filename(gpointer dialog) {
    if (filename) g_free(filename);
    filename=strdup(gtk_file_selection_get_filename(GTK_FILESELECTION(dialog)) );
    gtk_widget_hide(GTK_WIDGET(dialog));
    gtk_widget_destroy(GTK_WIDGET(dialog));
}
void open_cb(gpointer data) {
    gchar *text;
    gsize len;
    GtkWidget *dialog=gtk_file_selection_new("Open file");
    g_signal_connect(G_OBJECT(dialog->ok_button),"clicked",
	    G_CALLBACK (update_filename), (gpointer) dialog); 
    g_signal_connect(G_OBJECT(dialog->cancel_button),"clicked",
	    G_CALLBACK (gtk_widget_destroy), (gpointer) dialog); 

    gtk_run_dialog( GTK_DIALOG(dialog) );
    if (!filenme) {
	perror("You did not select a file."); return ;
    }
    if (!g_file_get_contents(filename,&text,&len,NULL)) {
	perror("could not open file"); return ;
    }
    gtk_text_buffer_set_text(buffer,text,-1);
}
void try_save() {
    FILE *file;
    gchar *text;
    GtkTextIter *iter1,*iter2;
    gtk_text_buffer_get_start_iter(buffer,iter1);
    gtk_text_buffer_get_end_iter(buffer,iter2);
    text=gtk_text_buffer_get_text(buffer,iter1,iter2,FALSE);
    file=fopen(filename,"w+");
    if (!file) {
	perror("could not open file for writting"); return ;
    }
    if ( fputs (text, file) < 0 ) 
	perror("could not write to file");
    fclose(file);
    if (text) g_free(text);
}
void save_cb(gpointer data) {
    if (filename) {
		try_save();
    } else	save_as_cb(0);
}
void save_as_cb(gpointer data) {
    GtkWidget *dialog=gtk_file_selection_new("Save file as ...");
    g_signal_connect(G_OBJECT(dialog->ok_button),"clicked",
	    G_CALLBACK (update_filename), (gpointer) dialog);
    gtk_run_dialog( GTK_DIALOG(dialog) );
    if (!filenme) {
	perror("You did not select a file."); return ;
    }
    try_save();
}
void about_cb(gpointer data) {
	g_print("gtk-ez-edit - GTK+ Easy Text Editor
		a program by Muayyad AlSadi<alsadi[AT]gmail[DOT]com>\n");
}

لاحظ استعمال GtkItemFactory لتوليد القائمة بسهولة من منظومة من GtkItemFactoryEntry التي تحتوي على مسار خيار القائمة ("_" تعني حرف مسطر) تفصله "/"، ثم سلسلة نصية تمثل المفتاح الساخن، ثم الوظيفة التي يستدعيها ثم رقم يمرر لتلك الوظيفة ثم سلسلة تمثل نوع هذا الخيار NULL ليكون الخيار مجرد نص، أو من مخزن Stock بواسطة "<StockItem>" ، أو أن هذا الخيار له فروع"<Branch>" وهناك خيارات خاصة مثل "<CheckItem>" و "<ToggleItem>" و "<RadioItem>" لوضع خيارات نحدد واحد منها أو نفعلها ونثبطها، ويمكن وضع فواصل بواسطة "<Separator>" أو "<Tearoff>" والفرق أن الأخيرة تعمل خط منقط عند النقر عليه تخرج محتوياته على شكل نافذة عائمة. وأخيراً نحدد معرف StockItem أو الصورة إن لزم. لقد سمينا أصل كل الفروع "<main>" وطلبنا مؤشر على الكائن الممثل له الذي سيمثل سطر القوائم.

GNOME ez-edit

لاخظ أننا وضعنا صندوق عرض النص داخل نافذة GtkScrolledWindow لتوفر لنا أشرطة تمرير Scrolled bars وذلك عندما يكبر صندوق عرض النص. أما صندوق حوار اختيار ملف gtk_file_selection المستعمل عند فتح أو حفظ الملف فهو مشروح في الفصل بعد التالي.

 تلميح

عدل البرنامج بحيث يعرض رسالة بواسطة GtkMessageDialog عند الخروج أو محاولة فتح ملف آخر بأن "الملف تغيّر، هل تريد المتابعة دون حفظ التغييرات ؟" وذلك باستعمال gtk_text_buffer_get_modified(buffer) لمعرفة فيما إذا كان قد تغيير أم لا وبعد تخزين الملف نستعمل gtk_text_buffer_set_modified(buffer,FALSE) لنعلن أن الملف خزّن ولم يتغيّر بعد.

تعتبر GtkTextView أداة قوية ليس لعمل محررات النصوص text editors فحسب بل لما هو أكثر تعقيداً من ذلك مثل معالجات النصوص word processors أو متصفحات الإنترنت browsers. إذ يمكن أن يحتوي كائن GtkTextView على نصوص ملونة وصور وأزرار وجداول أو أي كائن آخر.

لكل GtkTextView يوجد عضو يسمى GtkTextBuffer يمثل النص يمكن الحصول على مؤشر له بواسطة buffer=gtk_text_view_get_buffer(txt) حيث buffer هي مؤشر من نوع GtkTextBuffer و txt هو مؤشر لكائن GtkTextView (ولكننا نعرفه من نوع GtkWidget). لاحظ في مثال محرر النصوص السابق كيف حددا محتويات هذا الكائن بواسطة gtk_text_buffer_set_text عند فتح الملف، وكيف استقبلناها بواسطة gtk_text_buffer_get_text عند حفظه. الصنف GtkIter يستخدم ليشير إلى موقع داخل النص ولكنه يصبح غير صالح (ولا حتى يشير لمنطقة خطأ) عند القيام بأي تعديل على النص قبله، يمكن استعمال الوظيفة gtk_text_buffer_get_start_iter التي تأخذ مؤشرين (محجوزان مسبقاً) إلى GtkTextBuffer و GtkIter فتعمل على جعل الأخير يمثل الموقع في بداية النص كذلك الأمر مع gtk_text_buffer_get_end_iter، أما gtk_text_buffer_get_iter_at_offset فتأخذ معاملاً رقماً صحيحاً ثالثاً هو الإزاحة بالمحارف (الحمد لله أنها ليست بالبايتات) عن بداية النص. الوظيفة gtk_text_buffer_get_bounds التي تأخذ ثلاث مؤشرات محجوزة مسبقاً، واحد لGtkTextBuffer وإثنان ل GtkIter ليمثلا موقع بداية ونهاية التحديد (التظليل). هناك الكثير من الوظائف ذات الصلة منها

void gtk_text_buffer_get_iter_at_line(buffer,iter_ptr,line_no_from_0);
void gtk_text_buffer_get_iter_at_mark(buffer,iter_ptr,mark_ptr);
void gtk_text_buffer_get_iter_at_child_anchor(buffer,iter_ptr,anchor_ptr);
بعد أن نأخذ موقع GtkIter يمكنا أن نضيف نصاً هناك بواسطة gtk_text_buffer_insert وذلك بتمرير مؤشر لGtkTextBuffer ثم للموقع GtkIter ثم السلسلة النصية ثم -1 إذا كنت تريد تحديد النهاية تلقائياً (بواسطة صفر النهاية) أو بتمرير طول السلسلة. كما يمكك أن تحذف نصاً معيناً gtk_text_buffer_delete بتمرير مؤشرات ل GtkTextBuffer و GtkIter واحد للبداية منطقة الحذف وآخر لنهايتها. يمكن أن ندرج صورة بواسطة gtk_text_buffer_insert_pixbuf حيث نمرر ثلاث مؤشرات واحد ل GtkTextBuffer وآخر ل GtkIter لتحديد الموقع وثالث GdkPixbuf.للصورة التي حملتها مسبقاً بواسطة مكتبة GDK. المؤشر cursor هو أحد فروع نوع خاص من المواقع داخل النص تسمى العلامات GtkTextMark وهذا النوع وعلى عكس GtkIter يظل صالحاً حتى بعد تعديل النص ويمكن أن تكون العلامة منجذبة لليمين كالمؤشر العادي في اللغة الإنجليزية حيث يتحرك إلى الطرف اليمين من الجزء المضاف عند حشر نص (بالطباعة أو باللصق) ويمكن أن تكون منجذبة لليسار. لإضافة نص في الموقع الحالي للمؤشر نستعمل gtk_text_buffer_insert_at_cursor تماماً مثل gtk_text_buffer_insert دون معامل GtkIter. يمكنك أن تعمل علامة في النص بواسطة gtk_text_buffer_mark مع تمرير مؤشر ل GtkTextBuffer ثم سلسلة نصية هي اسم لتسهيل التعامل معها (ليكن NULL إذا لم ترغب باستعماله) ثم مؤشر GtkIter لتحديد موقع المؤشر ثم حدد هل المؤشر منجذب لليسار. توفر المكتبة علامتان اسم كل منهما "insert" و "selection_bound" اللذان يمثلان موقع المؤشر إذا تساويا وإلا فإنهما يشيران إلى طرفي التحديد. يمكن الحصول على مؤشر للعلامة إذا قدمت اسمها بعد GtkTextBuffer للوظيفة gtk_text_buffer_get_mark. يمكن تغيير مكان العلامة بواسطة gtk_text_buffer_move_mark التي تأخذ مؤشرات GtkTextBuffer ثم GtkTextMark ثم GtkIter ويمكن أيضاً عمل ذلك باسم العلامة بواسطة gtk_text_buffer_move_mark_by_name حيث يصبح المعامل الثاني هو سلسلة نصية تمثل اسم العلامة. بهذه الطريقة يمكنك عمل منطقة تحديد(تظليل) وذلك بتحريك insert و علامتي selection_boun
gtk_text_buffer_move_mark_by_name(buffer,"selection_bound",iter1);
gtk_text_buffer_move_mark_by_name(buffer,"insert",iter2);
ولتحريك المؤشر انقل العلامتين إلى نفس الموقع ولكن هذا سيؤدي لظهور مؤقت لمنطقة تحديد ثم اختفائها، طريقة أفضل قد تكون بواسطة الوظيفة gtk_text_buffer_place_cursor التي تأخذ مؤشرين لكل من GtkTextBuffer و GtkIter. توفر Gtk الوصول لنوعين من Clipboards للقيام بعمليات النسخ واللصق هما GDK_SELECTION_CLIPBOARD و GDK_SELECTION_PRIMARY للحصول على مؤشر لأي منهما استعمل gtk_clipboard_get مع تحديد أي منهما تريد
GtkClipboard *clipboard;
clipboard=gtk_clipboard_get(GDK_SELECTION_PRIMARY);
وبعد ذلك تستطيع القيام بالقص والنسخ واللصق بواسطة
gtk_text_buffer_cut_clipboard(buffer,clipboard,default_editable)ك
gtk_text_buffer_copy_clipboard(buffer,clipboard)ك
gtk_text_buffer_paste_clipboard(buffer,clipboard,iter,default_editable);
وفي الأخير للصق النص في مكان المؤشر ضع NULL مكان iter. كما يمكن حذف النص المحدد دون نسخه وذلك باستدعاء
gtk_text_buffer_delete_selection(buffer,interctive,default_editable)
في الوظائف السابقة تكون interctive أو default_editable إما TRUE أو FALSE، الوظيفة التي توصف بأنها interactive لا تقوم بالتعديل المطلوب إلا إذا كانت المنطقة المتأثرة تحمل العلامة editable أي يمكن تعديلها، والخيار default_editable يحدد قيمة العلامة editable للمنطقة الجديدة.

إن أهم ميزة يوفرها GtkTextView هو إمكانية تحرير وعرض نص مرقوم سمات مختلفة مثل لون النص والأرضية وحجم الخط وصفاته وغيرها الكثير، لعمل ذلك أولاً اعمل راقمة جديدة وأعطها اسماً لتسهيل التعامل وحدد سماتها وكل ذلك باستدعاء gtk_text_buffer_create_tag وتمرير مؤشر ل GtkTextBuffer ثم اسم ثم الخاصية ثم قيمتها وهكذا وأخيراً NULL تعيد هذه الوظيفة مؤر من نوع GtkTag مثلاً

gtk_text_buffer_create_tag(buffer,"big-red",
    "font","Sans 20","weight",PANGO_WEIGHT_BOLD,
    "style",PANGO_STYLE_ITALIC,"color","#FF0000",NULL);
لتطبيق هذه الراقمة على منطقة من النص نستدع gtk_text_buffer_apply_tag متبوعة بمؤشر على GtkTextBuffer وآخر إلى GtkTag ثم موقع بداية ونهاية المنطقة التي تريد تطبيق هذه الراقمة بها، الموقعا نحددهما بمؤشري GtkIter. وربما من الأسهل استعمال الاسم كما في المثال:
gtk_text_buffer_apply_tag_by_name(buffer,"big-red",iter1,iter2)
في أغلب برامج معالجات الكلمات يوجد زر على سطر الأدوات يجعل النص محدد ثخين، فلو كان لدينا راقمة اسمها "b" تعمل ذلك فإن الوظيفة المتربطة مع ضغط ذلك الزر يمكن أن تحتوي:
    GtkIter A,B;
    gtk_text_buffer_get_bounds(buffer,A,B);
    gtk_text_buffer_apply_tag_by_name(buffer,"b", &A,&B);
بنفس الطريقة نستعمل gtk_text_buffer_remove_tag و gtk_text_buffer_remove_tag_by_name لإلغاء راقمة معينة.

لقد تحدثنا عن تحديد المواقع داخل النص بواسطة GtkIter و GtkTextMark ولكن هناك نوع ثالث يسمى Anchor تستخدم في إدراج كائنات أخرى كالأزرار أو الجداول أو الصور المتحركة وغيرها داخل GtkTextView، المثال التالي يدرج صورة متحركة من ملف animation.gif إلى كائن النص.

    GtkIter A;
    GtkTextChildAnchor *anchor;
    GtkWidget *widget;
    widget=gtk_image_from_file("animation.gif");
    gtk_text_buffer_get_end_iter(buffer,&A);
    anchor=gtk_text_buffer_create_child_anchor(buffer,&A);
    gtk_text_view_add_child_at_anchor(view,widget,anchor);

8.3.9 التصميم باستعمال الجداول

إذا لاحظت في مثال جمع رقمين ستجد أن صناديق العناوين وصناديق الإدخال غير مرتبة عمودياً، يمكنك أن ترتبها بتغير الترتيب بحيث تقسم النافذة عمودياً بواسطة GtkHBox لنضيف فيها كائنين من نوع GtkVBox بجانب بعضهما على نفس الحافة عمودياً ونكدس في الأولى 3 صناديق عناوين وزر OK وفي الأخرى 3 صناديق إدخال و زر Cancel ولكن في هذه الحالة لا نضمن أن يكون صندوق العنوان محاذياً لصندوق الإدخال الذي يعبر عنه! لحل هذه المشكلة لدينا الجداول أولاً تخيل خلايا جدول مخفيٍ تحيط بكل كائن ثم حدد أكبر عدد من الصفوف والأعمدة اللازمة (يمكن أن تكون بعض الخلايا فتحت على بعض للمزيد من المساحة) وتذكر أن أي شكل مهما كان معقداً يمكن تصميمه بهذه الطريقة انظر إلى حيلة الجدول المخفي في فصل "2.3 برامج المكتب

Sample on Tables

لتنفيذ التصميم عرف مؤشر إلى GtkWidget (هو في الحقيقة ل GtkTable) ثم استدع gtk_table_new ومرر لها عدد الصفوف فعدد الأعمدة ثم حدد إذا كنت تريد أن تكون الخلايا متساوية في الحجم (غالباً لا). يمكنك تغيير عدد الصفوف أو الأعمدة بواسطة gtk_table_resize مع تمرير مؤشر للجدول ثم عدد الصفوف والأعمدة الجديدين. الجدول عبارة عن خلايا داخل شبك grid الذي هو نقاط لها احداثيين، تحدد الخلية بنقطتين على الشبك، جدول بأربعة صفوف وثلاث أعمدة يحتوي الاحداثيات العمودية 0 و 1 و 2 و 3 و 4 والأفقية هي 0 و 1 و 2 و 3.

لنضع كائن في خلية على هذا الجدول نستعمل gtk_table_attach ونمرر لها الجدول ثم الكائن ثم الاحداثييان الذان يحددان على أي الأعمدة تمتد الخلية (مثلاً 2،3) ثم الاحداثييان الذان يحددان على أي الصفوف تمتد الخلية (مثلاً 3،4) ومن ثم خيارات التمدد الأفقية فالعامودية وهما من بين GTK_EXPAND و GTK_SHRINK و GTK_FILL ويمكن استعمال "|" لأكثر من واحدة ويمكن أن لا تكون أياً منها بوضع صفر، الأولى تجعل الكائن الصغير يتمدد ليملئ كامل الخلية والثانية تجعل الكائن الكبير يتقلص ليناسب الخلية والأخيرة تجعله على قدرها وصفر ليبقى على حاله في حالة إعادة التحجيم، وأخيراً نمرر مقدار المسافات المتروكة على جانبي الكائن ومن فوقه وتحته

أحد الأمثلة استخدام الجداول هو تصميم واجهة آلة حاسبة بها زرا الجمع "+" والمساواة "=" طويلان عمودياً وزر الصفر طويل بالعرض.

GTK+ calculator
   table = gtk_table_new(6,4,TRUE);
   entry = gtk_entry_new();
   gtk_table_attach(table,entry,0,4,0,1,
    GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,3);
   btn_off = gtk_button_new_with_label("off");
   btn_div = gtk_button_new_with_label("/");
   btn_mult = gtk_button_new_with_label("*");
   btn_sub = gtk_button_new_with_label("-");

   btn_add = gtk_button_new_with_label("+");
   btn_eql = gtk_button_new_with_label("=");
   btn_dot = gtk_button_new_with_label(".");
   btn0 = gtk_button_new_with_label("0");
   btn1 = gtk_button_new_with_label("1");
   btn2 = gtk_button_new_with_label("2");
   btn3 = gtk_button_new_with_label("3");

   btn4 = gtk_button_new_with_label("4");
   btn5 = gtk_button_new_with_label("5");
   btn6 = gtk_button_new_with_label("6");
   btn7 = gtk_button_new_with_label("7");
   btn8 = gtk_button_new_with_label("8");
   btn9 = gtk_button_new_with_label("9");
   gtk_table_attach(table,btn_off, 0,1,1,2,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn_div, 1,2,1,2,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn_mult,2,3,1,2,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn_sub, 3,4,1,2,GTK_FILL,GTK_FILL,3,3);

   gtk_table_attach(table,btn_add,3,4,2,4,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn_eql,3,4,4,6,GTK_FILL,GTK_FILL,3,3);

   gtk_table_attach(table,btn0,0,2,5,6,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn_dot,2,3,5,6,GTK_FILL,GTK_FILL,3,3);

   gtk_table_attach(table,btn1,0,1,2,3,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn2,1,2,2,3,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn3,2,3,2,3,GTK_FILL,GTK_FILL,3,3);

   gtk_table_attach(table,btn4,0,1,3,4,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn5,1,2,3,4,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn6,2,3,3,4,GTK_FILL,GTK_FILL,3,3);

   gtk_table_attach(table,btn7,0,1,4,5,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn8,1,2,4,5,GTK_FILL,GTK_FILL,3,3);
   gtk_table_attach(table,btn9,2,3,4,5,GTK_FILL,GTK_FILL,3,3);

البرنامج السابق لجمع رقمين يمكن أن يصمم باستعمال الجداول بحذف كل ما يتتعلق ب GtkVBox و GtkHBox واستعمال الجدول كما يلي

    GtkWidget table;
    table=gtk_table_new(4,6,FALSE);
    gtk_container_add(GTK_CONTAINER (win),table);
    gtk_table_attach(table,label1, 0, 3, 0, 1, 0,0 ,0,0);
	gtk_table_attach(table,entry1, 3, 6, 0, 1, 0,0 ,0,0);
    gtk_table_attach(table,label2, 0, 3, 1, 2, 0,0 ,0,0);
	gtk_table_attach(table,entry2, 3, 6, 1, 2, 0,0 ,0,0);
    gtk_table_attach(table,label3, 0, 3, 2, 3, 0,0 ,0,0);
	gtk_table_attach(table,entry3, 3, 6, 2, 3, 0,0 ,0,0);
    gtk_table_attach(table,ok, 2, 4, 3, 4, 0,0 ,0,0);
لقد استعملت جدولاً به 6 خلايا في الصف و4 خلايا في العمود، صناديق العنونة والإدخال كل منها يحتوي 3 خلايا أفقية متحدة (ما بين 0 إلى 3 أو 3 إلى 6) وخلية عمودياً أما زر موافق فهو يمتد في ثلث المساحة في الوسط أي خليتين أفقيتين متحدتتين (من 2 إلى 4) عدل السطر table=gtk_table_new(4,6,FALSE); ليصبح table=gtk_table_new(4,6,TRUE); لترى هذه النسب بوضوح.

إذا لم ترضك أي من GtkVBox أو GtkHBox أو GtkTable فإنه عليك أن تستعمل GtkFixed أو GtkLayout (الأخيرة تحتوي أشرطة تمرير Scrollers تلقائية) حيث تمرر الإحداثيات السينية والصادية لكل كائن تضيفه وهذا أمر مرهق ولا يعطي نتائج جيدة إلا إذا كان التصميم يتطلب التعامل مع المواقع بالبكسيلات.

8.3.10 صناديق الحوار

تحتوي gtk على الكثير من صناديق الحوار الجاهزة منها صندوق حوار الرسالة ، إذا كنت تريد أن تظهر رسالة بسرعة ودون الكثير من العناء يمكنك ذلك باستعمال GtkMessageDialog فهو ببساطة printf هذه مثال يوضح العملية

/* ... */
GtkWidget *dialog;
dialog=gtk_message_dialog_new(
	win1,GTK_DIALOG_MODAL,
	GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
	"ERROR: you can't devide %d by zero",i
	);
gtk_run_dialog( GTK_DIALOG(dialog) );
gtk_widget_destroy(dialog);
/* ... */
هنا يظهر رسالة عليها رسمة توضح أنها رسالة خطأ تحتوي على زر اغلاق تظهر هذه الرسالة فوق نافذة اسمها win1 وتكون الرسالة من نوع MODAL أي تجمد النافذة الأب وتبقى فوقها ويبقى ينتظر منك أن تغلقها . الصيغة العامة لها هي
gtk_message_dialog_new(WINDOW,FLAGS, MESSAGE_TYPE,BUTTONS, "a message or a format,just like printf",...); حيث WINDOW هي النافذة التي يتبع لها يمكن أن تكون NULL ، FLAGS هي خصائص الصندوق وهي موضحة في الجدول أدناه، MESSAGE_TYPE هي نوع الرسالة وهي تحدد الأيقونة التي ترافق الرسالة الأنواع هي كما في الجدول أدناه ، أما BUTTONS فهي تحدد الأزرار الموجودة في مثالنا زر إغلاق واطقم الأزرار موضحة في الجدول أدناه

خيارات صندوق الحوار FLAGS
GTK_DIALOG_MODAL فوق النافذة الأب ويجمدها
GTK_DIALOG_DESTROY_WITH_PARENT يغلق النافذة الأب عند إغلاقه
GTK_DIALOG_NO_SEPARATOR لإزالة الخط الفصل بين المنطقة العلوية ومنطقة الأزرار
نوع الرسالة MESSAGE_TYPE
GTK_MESSAGE_INFO معلومات
GTK_MESSAGE_WARNING تحذير
GTK_MESSAGE_QUESTION سؤال
GTK_MESSAGE_ERROR خطأ
أطقم الأزرار BUTTONS
GTK_BUTTONS_NONE دون أي زر
GTK_BUTTONS_OK زر موافق
GTK_BUTTONS_CLOSE مع زر إغلاق
GTK_BUTTONS_CANCEL مع زر إلغاء
GTK_BUTTONS_YES_NO مع زرين هما "نعم" و"لا"
GTK_BUTTONS_OK_CANCEL مع زرين هما "موافق" و"إلغاء"

كل صناديق الحوار يمكنك أن تضيف عليها أزرار كما تريد، ربما تفضل ذلك مع GTK_BUTTONS_NONE الذي يكون بلا أزرار ، يمكن اضافته كما في المثال gtk_dialog_add_button(GTK_DIALOG(dialog),"Click me",1); حيث Click me هو النص الموجود على الزر و الرقم هو أي رقم (موجب لما تضيفه أنت وسالب للمسجل في gtk ) ليمكنك أن تستعمله لتعرف أي زر تم الضغط عليه ويمكنك أن تستعمل مخازن gtk التي تحتوي على الكثير من الأزرار الجاهزرة مثلاً gtk_dialog_add_button(GTK_DIALOG(dialog),GTK_STOCK_APPLY,GTK_RESPONSE_APPLY); ويمكنك اضافتها بطريقة أخرى نتحدث عنها لاحقاً.

بعد حجز الصندوق يمكن عرضه على أنه نافذة عادية أو ببساطة يمكن استدعاء gtk_run_dialog( GTK_DIALOG(dialog) ); هنا تحول هذه الوظيفة الصندوق إلى modal وتعرضه ثم تنتظر أن تستجيب له وتعيد رقم معيناً يمثل الزر الذي تم ضغطه ويمكن أن يكون من الجدول أدناه ،ويمكن أن يكون من الأزرار التي أضفتها

القيم التي يعيدها gtk_run_dialog
GTK_RESPONSE_OK عند اختيار "موافق"
GTK_RESPONSE_CANCEL عند اختيار "إلغاء"
GTK_RESPONSE_CLOSE عند اختيار "إغلاق"
GTK_RESPONSE_YES عند اختيار "نعم"
GTK_RESPONSE_NO عند اختيار "لا"
GTK_RESPONSE_APPLY عند اختيار "تطبيق"
GTK_RESPONSE_HELP عند اختيار "مساعدة"

لعمل صندوق حوار عام يمكن استخدام GtkDialog واضافة الكائنات فيه أو يمكن استعمال الصناديق الجاهزة منها GtkMessageDialog الذي تحدثثنا عنه ومنها أيضا GtkColorSelectionDialog و GtkFileSelection و GtkFontSelectionDialog. كل ما تحدثنا عنه في GtkMessageDialog ينطبق على باقي صناديق الحوار في gtk

في أي صندوق حوار فإنه يقسم لمنطقتين الأولى هي vbox والثانية action_area تحتوي هذه الأخيرة الأزرار لنفرض أن لديك صندوق حوار اسمه dialog يمكنك أن تصل إليهما بالطريقة التالية (GtkDialog *)dialog->vbox و (GtkDialog *)dialog->action_area أو بالإختصار GTK_DIALOG(dialog)->vbox و GTK_DIALOG(dialog)->action_area مثلاً لإضافة GtkEntry *entry1 إلى المنطقة العلوية استعمل gtk_container_add( (GtkContainer *)((GtkDialog *)dialog->vbox),entry1); أو بكلمات أخرى gtk_container_add(Gtk_CONTAINER(GTK_DIALOG(dialog)->vbox),entry1);

8.3.11 المزيد من الكائنات

هناك الكثير من الكائنات يمكنها أن تقوم بمعظم الأشيء التي قد تخطر ببالك مثلاً GtkImage التي تعرض الصور والرسوم المتحركة بمختلف أنواعها ،ببساطة استعمل image1=gtk_new_image_from_file("path/to/image.png"); ثم ضعها في النافذة وأظهرها. لدينا GtkCalendar لعرض التقويم ، ولدينا GtkCombo و GtkOptionMenu لعرض قائمة إختيارات منسدلة تظهر عند نقر سهم موجود عليها ، وكما لدينا الزر العادي GtkButton لدينا زر GtkToggleButton وهو زر متقلب بين وضعين ولدينا GtkCheckButton الذي يعرض مربع تنقر عليه فيضع صح (يمكن أن يكون أي شيء آخر حسب المؤثر المستخدم) وهناك GtkRadioButton وهو عبارة عن زر يمكنك من اختيار واحد من مجموعة منها بحيث يكون واحد مضاء فقط ، يمكن أن تحديد المجموعة ب GtkVBox أو GtkHBox . و يمكنك أن نستخدم GtkFrame لتحيط بهم لإعطاء شكل أنيق لهم ، ونستعمل GtkSpinButton وهو عبارة عن مكان لإدخال رقم مع سهمين متعادين لزيادة الرقم وانقاصه. يمكن استخدام GtkHandleBox ثم وضع حاوية بها مثل GtkToolBar لعمل جزء طافٍ من النافذة يمكن تحريكه. نستخدم GtkHSeparator أو GtkVSeparator لرسم خط يفصل بين الكائنات. ونستخدم GtkProgressBar لتبيان سير العملية على شكل نسبة مئوية أو مجرد حركة. لديك مسطرة عامودية وأفقية GtkVRuler و GtkHRuler. ولإختيار رقم بجر صندوق دحرجة GtkVScrollbar و GtkHScrollbar أو بتحريك مربع التدرج GtkHScale و GtkVScale . بل وحتى تحديد منحى مثل الموجود في gimp باستعمال GtkCurve. لعمل قائمة list أو شجرة tree نستعمل GtkTreeView لأن القائمة هي شجرة دون أفرع . ويمكن تلقي ومعالجة أحداث من كائنات لا تملك أحداث بوضعها داخل GtkEventBox

هناك المزيد من الصنوف والظائف الإضافية ل GTK توجد في حزم مكتبية أخرى مثل GtkOpenGlArea الموجودة في حزمة libgtkglarea لعمل رسومات بطريقة OpenGL. كما ويمكنك أن تعمل كائنات خاصة بك.

8.3.12 مكتبة غنوم

من بين الحزم التي تضيف صنوف ووظائف إضافية libgnome و libgnome-ui طبعاً، حيث توفر وسائل للتخاطب من مركز تحكم غنوم وتسجيل ملفات المساعدة واستعمال مراقب الصوت esound، ونظام موحد لسطر القوائم وقوائم popup وأسطر الأدوات، وسطر حالة متطور أكثر وغيرها الكثير. لاستعمال مكتبة غنوم ضع include للملف <libgnome/libgnome.h> في بداية البرنامج، وفي مراحلة مبكرة داخل main استدعِ

gnome_program_init(domain, ver, LIBGNOMEUI_MODULE,
    argc, argv, GNOME_PARAM_NONE);
يمكنك وضع بعض الخيارات قبل GNOME_PARAM_NONE على صورة اسم الخيار (مثل GNOME_PARAM_ENABLE_SOUND)ثم قيمته.

توفر مكتبة غنوم الكثير من الوظائف المساعدة التي لا علاقة لها بالكائنات الرسومية بل توفر عليك الكثير من التعب مثل سلسلة(مجموعة بالمعنى اللغوي) وظائف gnome_execute_* ، حيث * يمكن أن تكون async و shell و terminal_shell التي تنفذ برنامج في الخلفية بتمرر اسم البرامج على منظومة) أو في الثانية على شكل سلسلة نصية تمرر لمفسر الأوامر (مثل bash) أو كما في الأخيرة تنفذ برنامج بنفس الطريقة الثانية لكنها تظهر نافذة terminaal مثل gnome-terminal أو xterm. سلسلة وظائف gnome_config_* لقراءة أو كتابة إعدادات برنامجك داخل سجلات غنوم. وظيفة gnome_help_display(file_name,link,error) تعرض المساعدة الخاصة ب file_name بواسطة مركز مساعدة غنوم gnome help center أي ghelp. الوظيفة gnome_url_show(url,error) تعرض url (سواء أكان ملف أو موقع) من خلال البرامج المناسب مثلاً لعرض ملف pdf دون أن تزعج نفسك كيف مرر اسم الملف إلى هذه الوظيفة. لتشغيل ملف صوتي استعمل gnome_sound_play مع تمرير اسم الملف لها، ولكن قبل ذلك عليك تفعيل الصوت بواسطة استدعاء gnome_sound_init وتمرير عنوان خادم الصوت (حالياً تدعم esd الذي يسمح بأن يشغل أكثر من برنامج الصوت دفعة واحدة دون أن يؤثر على الآخر) ببساطة يمكنك تمرير localhost، وقبل نهاية البرنامج (عند إنتهاء جميع ما يتعلق بالصوت) حرر أغلق الاتصال مع خادم الصوت gnome_shutdown().

كائنات غنوم الإضافية للواجهة الرسومية widgets موجودة في libgnomeui/libgnomeui.h فبعد عمل include سيتوفر لك الكثير من الكائات الجديدة أهمها GnomeApp. بدلاً من استعمال gtk_window_new(GTK_WINDOW_TOPLEVEL) استعمل gnome_app_new(internal_app_name,title) حيث نمرر لها سلسلتين نصيتين (معرف للبرنامج، وعنوان النافذة) كما يلي:

GtWidget *app;
app=gnome_app_new("demo","Welcome");
إذا عملت GtkMenuBar بأي طريقة (مثل GtkItemFactory) ضعها في نافذة التطبيق بالوظيفة gnome_app_set_menus(app,menubar). كذلك الأمر لصندوق الأدوات gnome_app_set_toolbar(app,toolbar) ولاحظ أنه سطر أدوات عائم يمكن تحريكه كما له قائمة popup، ولإضافة سطر الحالة استعمل gnome_app_set_statusbar(app,statusbar)، أما لب النافذة (منطقة العمل) حدده بواسطة gnome_app_set_contents(app,contents) ولا يمكن إضافة أكثر من كائن واحد لذا يمكنك جعله GtkTable أو GtkHBox أو GtkVBox.

توفر هذه المكتبة سطر حالة متطور من صنف GtkAppBar يمكن أن يحوي مؤشر العمل progress bar إضافة للحالة:

GtWidget *statusbar;
statusbar=gnome_appbar_new(TRUE,TRUE,GNOME_PREFERENCES_USER)
الأولى تحدد هل تريد مؤشر العمل has_progress ثم هل تريد نص الحالة has_status ، ثم متى يمكن التفاعل معه التي قد تكون GNOME_PREFERENCES_USER أو GNOME_PREFERENCES_NEVER أو GNOME_PREFERENCES_ALWAYS.

بطريقة مشابهة لتوليد القوائم بواسطة GtkItemFactory توفر هذه المكتبة وسيلة لتوليد جميع أنواع القوائم وسطور الأدوات وذلك بعمل تركيب منظومة من تراكيب GnomeUIInfo وتوفر عدد من الاختصارات macors لبنائها مثلاً

GNOMEUIInfo file_menu[]={
    GNOMEUIINFO_MENU_NEW_ITEM(label,tip,cb,data),
    GNOMEUIINFO_MENU_OPEN_ITEM(cb,data),
    GNOMEUIINFO_MENU_SAVE_ITEM(cb,data),
    GNOMEUIINFO_MENU_SAVE_AS_ITEM(cb,data),
    GNOMEUIINFO_SEPARATOR,
    GNOMEUIINFO_MENU_QUIT_ITEM(cb,data),
    GNOMEUIINFO_END
}
GNOMEUIInfo help_menu[]={
    GNOMEUIINFO_HELP(app_id), /* all rewgisted help topics for that app */
    GNOMEUIINFO_MENU_ABOUT_ITEM(cb,stock),
    GNOMEUIINFO_END
}
حيث cb هي الوظيفة التي تستدعى عند انتقاء ذلك الخيار مع تمرير data له، في المثال سابق استعملنا خيارات معدة مسبقاً، في المثال التي نستعمل خيارات خاصة بنا (من GtkStock أو بدونها)
GNOMEUIInfo foo_menu[]={
    GNOMEUIINFO_ITEM_STOCK(label,tip,cb,stock),
    GNOMEUIINFO_ITEM_NONE(label,tip,cb),
    GNOMEUIINFO_END
}
هذا بالنسبة للقوائم الفرعية أما القوائم المتفرعة فنستعمل الاختصارات التي تحتوي TREE ونعطيها مؤشر على منظومة الفرع مثلاً
GNOMEUIInfo main_menu[]={
    GNOMEUIINFO_MENU_FILE_TREE(file_menu),
    GNOMEUIINFO_MENU_EDIT_TREE(edit_menu),
    GNOMEUIINFO_SUBTREE("foo",foo_menu),
    GNOMEUIINFO_SUBTREE_HINT("foobar","status bar hint",foo_menu),
    GNOMEUIINFO_MENU_HELP_TREE(help_menu),
    GNOMEUIINFO_END
}
وكما لاحظت كل تركيب ينتهي ب GNOMEUIINFO_END. لعمل القائمة الممثلة بتلك المنظومة وإضافتها لنافذة التطبيق gnome_app_create_menus(app,main_menu)، يمكن إضافة ما تمثله على شكل صندوق أدوات مثلاً بواسطة gnome_app_create_toolbar(app,file_menu) التي تعمل صندوق أدوات بالخيارات التي عرفناها داخل file_menu وهي جديد وفتح وحفظ ثم حفظ باسم ثم ففاصل ثم خروج. يمكن أيضاً عمل قائمة popup بفس الطريقة
popup=gnome_popup_menu_new(popup_menu);
gnome_popup_menu_attach(popup,widget,data);

هناك الكثير الكثير من الكائنات الرسومية التي يمكنك أن تضيفها في برنامجك مثل:

gnome_entry_new() /* entry with history combo */
gnome_href_new(url,text)
gnome_date_edit_new(time_t,show_time_T_F,h24_T_F)
gnome_color_picker_new()
gnome_druid*
التي على الترتيب تعمل صندوق إدخال مع سهم لعرض آخر المدخلات واختيار أحدها، الثانية تعمل وصلة hyper link معاملها الأول هو الموقع والثاني هو النص الذي يظهر على الزر، الثالثة هي لعرض أو اختيار التاريخ والوقت المعامل الأول من نوع time_t الذي تحدثنا عنه في فصل 7.2 مكتبة سي القياسية libc المعامل الثاني هل تريد إظهار الوقت والثالث هل هو بصيغة 24 ساعة. الكائن الرابع لاختيار الألوان ، والأخير لعمل wizrads أو ما تسميه gnome باسم druids (ترجمتها في البرامج التجارية المعربة "معالجات" !!) وهي شاشة تحتوي بعض الأسئلة على شكل صناديق إدخال أو أزرار في عدة صفحات تنتقل بينها بزر تالي next ثم في النهاية تختار إنهاء finish.

المحتويات
حقوق النسخ والملكية الفكرة
ما هو لينكس؟
كيف تركب نظام لينكس؟
حقوق النسخ المرفوعة
وثائق التخويف

عرب-آيز
مجتمع لينكس العربي
موسوعة ثواب
موسوعة ويكيبيديا
تعريف البرمجيات الحرة
تعريف مفتوحة المصدر
LinuxToday
Linux.org
Linux.com
SlashDot
FreshMeat
LWN.net
توزيعات لينكس
النسخة الإسلامية لأوبنتو
عَرَبيان
جواثا (أول مسجد في أوروبا)
المزيد من التوزيعات هنا

إسلاميات
    برامج:
بريمج أوقات الصلاة
بريمج التقويم الهجري
    صوتيات:
محاضرات: قصص الأنبياء (نبيل العوضي)
أناشيد
اطلب نسختك مجاناً
لكي تصلك أقراص لينكس أوبونتو Ubuntu أصلية مجاناً والتوصيل مجاناً لن تدفع فلساً واحداً ولن تجبر على رؤية دعايات. كل ما عليك هو أن تنقر هنا.
مقالات
    تقنية:
تسجيل وتحويل الصوتيات
تعريف الماسح الضوئي في لينكس
    ساخرة:
من أجل ذلك لا تقرأ
الفيلة والصراع العربي الإسرائيلي
بلاغات
التبليغ عن إعلانات غير مرغوبة
عثرات وأخطاء إملائية
وصلات لا تعمل:

 

ننصح باستخدام متصفحات الوب الحرة، جرب ثعلب النار الآن

يمكنك الحصول على الكثير من البرامج الحرة عالية الجودة من هنا مجاناً
proud to be 100% Microsoft FREE GNU FDL
التدخين حرام

كن كحامل المسك ولا تكن كنافخ الكير

Generously Hosted by www.JadMadi.net

Previous Up مكتبة GTK وبرنامج glade Next
Copyright © 2007, Muayyad Saleh AlSadi