مكتبة 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);
|

|
إن صنف 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>" وطلبنا مؤشر على الكائن الممثل له
الذي سيمثل سطر القوائم.
|

|
لاخظ أننا وضعنا صندوق عرض النص داخل نافذة 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 برامج المكتب"،
|

|
لتنفيذ التصميم عرف مؤشر إلى 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 ويمكن استعمال "|" لأكثر من واحدة ويمكن
أن لا تكون أياً منها بوضع صفر، الأولى تجعل الكائن الصغير يتمدد ليملئ كامل
الخلية والثانية تجعل الكائن الكبير يتقلص ليناسب الخلية والأخيرة
تجعله على قدرها وصفر ليبقى على حاله في حالة إعادة التحجيم،
وأخيراً نمرر مقدار المسافات المتروكة على جانبي الكائن ومن فوقه وتحته
أحد الأمثلة استخدام الجداول هو تصميم واجهة آلة حاسبة بها زرا
الجمع "+" والمساواة "=" طويلان عمودياً وزر الصفر طويل بالعرض.
|

|
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.
|
| اطلب نسختك مجاناً |
|
لكي تصلك أقراص لينكس أوبونتو Ubuntu أصلية
مجاناً والتوصيل مجاناً لن تدفع فلساً واحداً ولن تجبر على رؤية دعايات.
كل ما عليك هو أن
تنقر هنا.
|
ننصح باستخدام متصفحات الوب الحرة، جرب ثعلب النار الآن
يمكنك الحصول على الكثير من البرامج الحرة عالية الجودة
من هنا مجاناً
التدخين حرام

كن كحامل المسك ولا تكن كنافخ الكير
Generously Hosted by www.JadMadi.net
|