GTK+ Programlama ve Sık Kullanılan Birimler

Başlatan sem, 10 Ocak 2011 - 18:26:19

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

sem

Forumda GTK+ programlama ile ilgili başlık olsun istediğim için bir katkım olsun diye başlığı açma gereği duydum. Çünkü son zamanlar GTK ve QT ile ilgili soruların sıklaşmaya başladığını görüyoruz.

Bu başlığı tam anlamıyla GTK öğrenmek için değil öğrenmek istiyorsanız okuyacağınız bir ön hazırlık gibi düşünebilirsiniz. Zaten her başlıktan sonra ilgili bağlantıyı vereceğim. Merak eden arkadaşlar daha detaylı anlatım için bu bağlantılara baş vurabilir. Kısaca şunlardan bahsedeceğim başlıkta:

1.)  GTK+ Nedir?
2.)  Programda  olaylar ve sinyaller
3.)  Pencereler
4.)  Düğmeler
5.)  Kontrol Düğmeleri
6.)  Labeller
7.)  Yazı Girişleri
8.)  Yatay kutular
9.)  Dikey Kutular
10.) Tablolar

Başlıkta GTK+ ile C geliştirilme üzerinde durulmuştur...

GTK nedir?

GIMP Toolkit ya da GTK+, bir çok platformlu grafiksel kullanıcı arayüzü geliştirme araç takımıdır. Qt ile beraber X Pencere Sistemi'nin en popüler araç takımıdır. GTK+ başlangıçta GNU Resim İşleme Programı için yazılmıştı. Şimdi GNU Projesi'nin bir parçası olarak LPGL lisansı altında ücretsiz olarak dağıtılmaktadır.

Kaynak:tr.wikipedia.org

Yani en basitinden söyleyecek olursam biz programlarımıza GUI geliştirmek için kullanacağız. Yani GTK sayesinde C ile yazdığımız bir programı uçbirimden çalıştırmak zorunda kalmayacağız.

C veya C++ ile GTK derlemek için şu paketlere ihtiyacınız olacak gcc, g++ ve libgtk2.0-dev, aşağıdaki komut ile kurabilirsiniz;

sudo apt-get install gcc g++ libgtk2.0-dev


Programlarınızı derlerken ise "gcc program.c -o program" komutu yeterli olmayacaktır. O nedenle derleme parametrelerinize "`pkg-config --libs --cflags gtk+-2.0`" kısmını ilave etmelisiniz. Yani derleme komutunuz aşağıdaki gibi olmalıdır (C derlemek için yani gcc kullanırken):

gcc program.c -o program `pkg-config --libs --cflags gtk+-2.0`


GTK ile sadece C değil PHP dahil bir çok dil geliştirebilirsiniz. Ben şimdiye kadar sadece C ile denediğim için bütün örneklerimi C üzerinden anlatacağım...


Şuradan başlayalım; bir GTK+ program şablonu aşağıdaki gibi olacaktır...

int main( int   argc, char *argv[] )
{
...
...
   gtk_init (&argc, &argv);
...
...
...

    gtk_main ();
    return 0;
}


Burada normalde C'de olmayan şu iki satır var;

gtk_init (&argc, &argv);

ve

gtk_main ();


Bu iki fonksiyonu bütün GTK programlarında kullanmalısınız. Çünkü ilk fonksiyon ("gtk_init (&argc, &argv)");

GTK araçlarını kullanabilmemizi sağlıyor ve komut satırı argümanlarını ayrıştırıyor. O nedene bir GTK fonksiyonunu çağırmadan önce mutlaka bu fonksiyonu çağırmalısınız. Tabii her fonksiyondan önce çağırmamıza gerek yok, program başında bir kere çağırmamız yeterli olacaktır...

gtk_main () fonksiyonunun işlevi ise; akış bu noktaya geldiğinde programı "zulaya yatıyor" gibi düşünebiliriz. Akış buraya geldiği zaman program oluşacak X olaylarını yakalamak için beklemede duruyor.

X olayı nedir?

Burada demek istediğim: Şöyle bir program yazdık diyelim; program açıldı bir tuşu var ve bu tuşa basınca bize bir mesaj verecek. İşte bu tuşa basma olayı bir X olayıdır. Programda her şeyi tanımladık program açıldı ve gtk_main() döngüsüne geldi diyelim,işte burada program bizim bir fare tuşuna basma, klavyeden bir tuş girme gibi olaylarımızı yakalamak için bekliyor diyebiliriz.


X olayı nasıl yakalanacak?

Bu işlemi yapmak için bir sinyal mekanizması geliştirilmiş ve biz de bu bu sinyal mekanizmasını kullanarak X olaylarını yakalamaya çalışacağız. Genel olarak akış şöyle olacak;

1.) Bir düğme oluştur (button)
2.) Düğmenin yakalayacağı X olayını belirt (örneğin tıklama)
3.) Düğme X olayını yakaladığında yapmak istenilen işlemleri belirt... (bu işlemler bir fonksiyon içerisinde belirtiliyor ve bu fonksiyona call back fonksiyonu deniliyor)
(Burada düğme sadece bir örnektir bu birim tabii ki değişebilir)

Çok basit bir örnek üzerinden gidelim;


#include <gtk/gtk.h>

static void hello( GtkWidget *widget,  gpointer   data )
{
    g_print ("Düğmeye basıldı\n");
}



static void destroy( GtkWidget *widget, gpointer   data )
{
    g_print("Kapatılıyor...\n");
    gtk_main_quit ();
}

int main( int   argc,  char *argv[] )
{
    GtkWidget *Pencere, *Dugme;    //Pencere değişkeni programımızın ana penceresi, Dugme ise düğmemiz olacak
   
    gtk_init (&argc, &argv);       // Bütük GTK programlarında olacağı gibi fonksiyonumuzu çağırdık

    Pencere = gtk_window_new (GTK_WINDOW_TOPLEVEL);  // Pencere oluşturuluyor
   
    g_signal_connect (Pencere, "destroy",  G_CALLBACK (destroy), NULL); // Pencere için sinyal yakalama fonksiyonu...

    Dugme = gtk_button_new_with_label ("İlk Düğme"); // Düğme oluşturuluyor
   
    g_signal_connect (Dugme, "clicked",  G_CALLBACK (hello), NULL);   // Düğme için sinyal yakalama fonksiyonu...
   
    gtk_container_add (GTK_CONTAINER (Pencere), Dugme); // Dugme değişkeni Pencere içerisine koyuluyor.
   
    gtk_widget_show (Dugme); // Eklenen Dugme'nin gösterilmesi sağlanıyor
   
    gtk_widget_show (Pencere); // Pencere değişkeninin gösterilmesi sağlanıyor
   
    gtk_main ();
   
    return 0;
}


NOT: Programı derlerken gerekli parametreleri unutmayın lütfen; derleme parametrelerine mutlaka    `pkg-config --libs --cflags gtk+-2.0`    kısmını ekleyin...
NOT2: Program çok küçük olarak açılacaktır, göremeyecekler için bilgilendirme geçeyim şimdiden dedim...


Pencere = gtk_window_new (GTK_WINDOW_TOPLEVEL);  // Pencere oluşturuluyor
   
g_signal_connect (Pencere, "destroy",  G_CALLBACK (destroy), NULL);


Bu kısımdan başlayalım... gtk_window_new(); fonksiyonu ile bir pencere ouşturuluyor (fonksiyon parameterelerinden daha sonra bahsedeceğim).

g_signal_connect(); -> Bu fonksiyon ise bir birimin (düğme, radiobutton, pencere...) istenilen sinyali yaymasını ve sinyalin yayılması durumda yapılacak olan işlemi belirlememizi sağlıyor.

1. parametre: Oluşan sinyali yayacak olan birimi gösteriyor. Bizim örneğimizde sinyal Pencere tarafından yayılıyor.
2. parametre: Yayılmasını istediğimiz sinyalin adı. Biz örneğimizde "destroy" sinyalinin Pencere tarafından yayılmasını istiyoruz. Bu sinyal pencereyi kapatmaya çalıştığımızda yayılıyor.
3. parametre: Bu parametre ile birimimiz sinyal oluşturduğunda çağırılacak olan fonksiyonu belirliyoruz. Yani örneğimizde adı "destroy" olan fonksiyonu çağrıyırıyoruz.
4. parametre: Sinyal fonksiyonuna göndermek istediğimiz parametre. Bir şey göndermek istemiyorsanız örneğimizdeki gibi NULL olarak geçebilirsiniz.

Toparlarsak bu fonksiyon ile şunu belirtmiş olduk: Pencere kapanmaya çalıştığında destroy sinyalini oluştursun, bu sinyal oluştuğunda da destroy fonksiyonunu çağırsın.

Çağırdığımız fonksiyonun prototipini inceleyecek olursak;

static void destroy( GtkWidget *widget, gpointer   data );

Fonksiyonun ilk parametresi örneğimiz için konuşacak olursak "Pencere" oluyor yani sinyalin yayıldığı birim. İkinci parametre ise g_signal_connect() fonskyisonu ile gönderilen parametre.

Bu prototip genel bir prototip oluyor. Yani başka birimler tarafından başka sinyaller yayıldığında fonksiyon parametrelerinde artış olabilir, buna dikkat etmemiz gerekiyor.

Programımızda oluşturduğumuz düğme için de bir sinyal ve sinyal fonksiyonu yazılmıştır... Düğme tıklanması durumunda yayılacak olan sinyal ve sinya yayıldığında akışın geçeceği fonksiyon belirlenmiştir... İlkini açıkladıktan sonra ikincisini anlayabilirsiniz diye düşünüyorum.

İlk örnekte dikkatimizi çeken durumlar:

1.) Pencere ile düğme aynı tür mü?
2.)  gtk_container_add (GTK_CONTAINER (Pencere), Dugme); bu fonksiyon ile düğmeyi doğrudan pencereye yerleştirdik, koordinatları belli değil, konumu belli değil, farklı birimler eklediğimizde nasıl olacak?

C1: Görünüşte evet. İkisini de GtkWidget türünden birer gösterici olarak tanımlıyoruz. Buradaki asıl dikkat etmemiz gereken durum bunların gösterici yani adres bilgisi tuttuğu. Bu adres bilgileri ise gerekli fonksiyonlar ile bizim için şekillendiriliyor diye tahmin ediyorum. Oluşturucu fonksiyonların prototipine bakarsak:

GtkWidget*   gtk_button_new_with_label (const gchar *label);
GtkWidget*   gtk_window_new  (GtkWindowType type);


İkisi de GtkWidget türünden bir adrese dönüş yapıyor. Fakat yapı itibari ile baktığımızda;

typedef struct _GtkWindow GtkWindow;
typedef struct _GtkButton GtkButton;


Bu şekilde farklı türler olarak tanımlanmış. Yani yapı olarak farklı olsalar da aynı türden adrese dönüyorlar, adresler içerisinde neler oluyor benim de hiç bir fikrim yok. Bilen arkadaşlar yardımcı olacaktır bize bu konuda sanırım.

Ek şahsi not: Widget* türünü standart C'deki void olarak düşünüyorum. Çünkü bu durum sadece pencere ve düğmeler değil genel olarak tüm birimler için geçerli. Hepsinin oluşturucu fonksiyonu bu türden bir adrese dönüyor fakat farklı yerlerde değişiklikler yapma imkanı sunuyor (düğmenin yazısını değiştirme, pencerenin konumunu ayarlama gibi...).

C2: GTK+'da tanımlanmış olan taşıyıcı (container) birimler mevcut. Bu taşıyıcılar diğer birimlerimizin lokasyonu ile ilgili ayarlar yapmamıza olanak sağlıyor. Az sonra bunlara da değineceğim.

NOT: Sinyalleri daha ayrıntılı incelemek için ve diğer sinyal fonksiyonlarını görmek için BU bağlantıyı kullanabilirsiniz...

Biraz  da birimleri tanıyalım.

PENCERELER

GtkWidget*   gtk_window_new  (GtkWindowType type);

Fonksiyonu ile oluşturuluyor. Bu fonksiyona göderdiğimiz parametre ile pencerenin türünü belirleyebiliriz. Değer olarak aşağıdakileri kullanabilirsiniz;

GTK_WINDOW_TOPLEVEL: Bu şekilde yaratılan bir pencere isim, kapatma, küçültme ve büyütme değerlerine sahiptir.
GTK_WINDOW_POPUP: Bu varsayılan olarak çerçevesiz doğal olarak isim ve düğmeler gibi özellikleri barındırmayan bir pencere yaratır.


void   gtk_window_set_title   (GtkWindow *window,  const gchar *title);

Penceremizin isminizi ayarlıyoruz. İlk parametre ismini değiştireceğimiz penceremiz, ikincisi ise penceremizin ismi. Burada ilk parametrenin GtkWindow olduğuna dikkat edin.

Değişkenleri GtkWidget olarak tanımlıyoruz, fakat ilgili fonksiyonlarda kendi türleri kullanılıyor. Bu durumlarda uyarı almamak için şu makroları kullanıyoruz;

GTK_WINDOW()
GTK_BUTTON()

...

Çeşitli örnekleri aşağılarda vereceğim.

void   gtk_window_set_resizable     (GtkWindow *window,   gboolean resizable);

ilk parametresi ile belirlediğimiz pencerenin kullanıcı tarafından boyutunun değiştirilip değiştirilemeyeceğini ayarlamamızı sağlar. İkinci parametreye TRUE girersek kullanıcı pencereyi yeniden boyutlandırabilir, FALSE girersek boyutlandıramaz.

gboolean   gtk_window_get_resizable  (GtkWindow *window);

Penceremizin yeniden boyutlandırılabilme durumunu elde etmemizi sağlar. Geri dönüş değeri TRUE ya da FALSE olabilir. Bu değerler yukardaki  fonskiyon ile aynı şeyleri ifade eder.

void   gtk_window_set_default_size   (GtkWindow *window, gint width, gint height);

Penceremizin açılışta alacağı boyutları belirtmemizi sağlar.


void  gtk_window_set_position   (GtkWindow *window,  GtkWindowPosition position);

İlk parametrede belirttiğimiz pencerenin açılacağı konumunu ikinci parametreye göre belirler. İkinci parametreye geçebileceğimiz değerler;

GTK_WIN_POS_NONE: Pencerenin yerleşmesi ile ilgili bir ayarlama yapılmaz
GTK_WIN_POS_CENTER: Pencereyi ekranın ortasında açar
GTK_WIN_POS_MOUSE: Fare imlecinin bulunduğu yerde açar
GTK_WIN_POS_CENTER_ALWAYS: Yeniden boyutlandırma ya da benzeri durumlarda da pencereyi ekrana ortalar

Pencereler ile ilgili bir çok fonksiyon daha mevcuttur.  İlgili fonksiyonlara http://library.gnome.org/devel/gtk/unstable/GtkWindow.html#GtkWindow.synopsis adresinden ulaşabilirsiniz.

ÖNEMLİ: Pencere tanımladığınız zaman "destroy" olayını daima yakalayın.



DÜĞMELER

GtkWidget*  gtk_button_new   (void);

ya da

GtkWidget*  gtk_button_new_with_label   (const gchar *label);

fonksiyonları ile oluşturulurlar. İki fonksiyon arasındaki fark; ikinci fonksiyon ile oluşturduğumuz düğmenin üzerindeki yazıyı ayarlayabiliyor olmamız. Fonskiyon parametresine düğmenin adını geçiyoruz.

Düğmeler ile ilgili diğer fonksiyonlara BU bağlantıdan ulaşabilirsiniz.


KONTROL DÜĞMELERİ (Check Box):

GtkWidget *gtk_check_button_new( void );

ya da

GtkWidget *gtk_check_button_new_with_label ( const gchar *label );

fonksiyonları ile oluşturulabilirler. Aralarındaki fark düğme fonksiyonlarındaki ile aynıdır.

void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,  gboolean   is_active );

Bu fonksiyon ile program içerisinden bir kontrol kutucuğunu işaretleyebilir ya da işaretli ise işareti kaldırabilirsiniz (tiklemekten bahsediyorum). İlk parametre ile ilgili kontrol kutucuğunu belirtiyoruz. Burada türün GtkToggleButton olduğuna dikkat edin.

İkinci parametrede TRUE ya da FALSE olabilir. TRUE kutucuğu işaretler, FALSE işareti kaldırır.


LABEL (Türkçesini bilmiyorum, bilen arkadaşlar söylerler ise gerekli düzeltmeyi yaparım)

GtkWidget*  gtk_label_new  (const gchar *str);

Fonksiyonu ile label oluşturuyoruz. Parametre olarak yazmasını istediğimiz yazıyı giriyoruz.

void   gtk_label_set_text  (GtkLabel *label,   const gchar *str);

Fonksiyon ile program içerisinden bir Label yazısını değiştiyoruz. İlk parametre yazısı değiştirilecek olan label, ikinci parametre ise yeni yazımı oluyor.

const gchar*  gtk_label_get_text   (GtkLabel *label);

Fonksiyon ile, parametrede belirttiğimiz label'ın yazısını elde ediyoruz.


Diğer label fonksiyonlarına BU bağlantıdan ulaşabilirsiniz.


YAZI GİRİŞLERİ (Text Entry)

Kullanıcıdan yazı girişi almak için kullanacağımız birim GtkEntry'ler..

GtkWidget*   gtk_entry_new  (void);

Bu fonksiyon ile yazı girişi alacağımız birimimizi oluşturuyoruz.

void   gtk_entry_set_text   (GtkEntry *entry, const gchar *text);

Bu fonksiyon ile birimimize program içerisinden yazı yazabiliyoruz. İlk parametrede yazıyı yazağımız birimi belirtiyoruz, ikinci parametremiz ise yazacağımız yazı oluyor

const gchar*  gtk_entry_get_text  (GtkEntry *entry);

Bu fonksiyon ile de birime girilmiş olan yazıyı elde edebiliyoruz. İlk parametre bir önceki fonksiyon ile aynı. İkincisi ise yazacağımız değil alacağımız yazı oluyor.

void   gtk_entry_set_max_length(GtkEntry *entry,  gint max);

Bu fonksiyon ile birimimize girilebilecek maksimum karakter sayısını belirtiyoruz. İlk parametre sınır getirilecek birimimiz ikincisi ise getireceğimiz sınır oluyor.

Program yazmaya başlamak için bilmemiz gereken temellerden taşıyıcılardan da bahsettikten sonra program yazmaya başlayabiliriz.


TAŞIYICILAR (CONTAINERS)

GTK+'da  taşıyıcı olarak kullanabileceğimiz bir çok birim var. Biz sadece bir kaç tanesinden bahsedeceğiz.

Taşıyıcılar GTK+ da paketleme mantığı ile çalışıyor. Yani birimlerimizi doğrudan penceremize eklemiyoruz. Önce bir kutu oluşturup bunu pencereye ekliyoruz. Daha sonra birimlerimizi bu kutuya ekliyoruz ve paketleme seçeneklerine göre kutumuz birimlerimizi paketliyor. Paketleme sırası ve bu sıra ile birimlerin lokasyonunu biz belirlemiş oluyoruz.

Paketleme ile ilgili daha geniş bilgilere BU bağlantıdan ulaşabilirsiniz.


Dikey Kutular (Vertical Box) ve Yatay Kutular (Horizontal Box):

Bu iki taşıyıcıyı aynı başlıkta incelememizin sebebi yapılarının ve fonksiyonlarının çok benzer olması. Örneğin üç tane düğmemiz (button) var diyelim. Bunları eğer bir dikey kutu içerisine yerleştirirsek yukardan aşağı ya da aşağıdan yukarı olarak sıralı bir görünüm elde etmiş oluruz, eğer bu düğmelerimizi bir yatay kutu içerisine yerleştirirsek sağdan sola ya da soldan sağa bir görünüm elde etmiş oluruz.


GtkWidget *  gtk_hbox_new  (gboolean homogeneous,  gint spacing);
GtkWidget *  gtk_vbox_new  (gboolean homogeneous,  gint spacing);


Görüdğünüz gibi oluştururken kullanılan fonksiyonlar hemen hemen aynı sadece bir harf fark ediyor... İlk fonksiyon bir yatay ikincisi ise bir dikey kutu oluşturuyor...

İki fonskiyonda da  birinci parametre, isminde de anlaşıldığı gibi homojenliği ayarlar. Eğer TRUE geçilirse içerisine yüklenen birimler homojen olarak dağılır, FALSE geçilirse ise homojenliğe dikkat edilmeden eklenen birimlerin hepsi sırası ile yan yana dizilir...  İkinci parametreler ise kutularımızın içine yüklediğimiz diğer birimlerin arasındaki boşluğun uzunluğunu verir...


Yatay ve dikey kutularımızı oluşturduk. Şimdi kutularımızın içerisine diğer birimleri yerleştirmeyi görelim...


void   gtk_box_pack_start(GtkBox *box, GtkWidget *child,  gboolean expand,  gboolean fill, guint padding);
void   gtk_box_pack_end(GtkBox *box,   GtkWidget *child,  gboolean expand,  gboolean fill, guint padding);


Fonksiyonlara baktıkça yatay ve dikey kutuların aynı başlıkta incelenmesi daha da anlam kazanıyor. Bu iki fonksiyonu hem yatay hem de dikey kutular için kullanabiliyoruz. Bu fonksiyonlar diğer birimleri (düğme, label gibi) kutularımıza paketlemimizi sağlıyor. İlk fonksiyon yani içerisinde "start" kelimesi geçen fonksiyon paketlemeye baştan başlıyor, bunun anlamı yatay kutu için soldan sağa, dikey kutu için yukarıdan aşağıya. İkinci fonksiyon ise yani içerisinde "end" geçen fonksiyon ise tam zıt şekilde paketlemeyi sondan yapıyor... Yani yatay kutu için sağdan sola, dikey kutu için aşağıdan yukarıya... Fonksiyonların parametreleri ise aynı şeyi ifade ediyor;

1. parametre: Paketleme işlemini yapacağımız kutumuz.
2. parametre: Paketlenecek olan birim.
3. parametre: Bileşen yerleştireceğimiz boşluğa ortalanır
4. parametre: TRUE geçilirse paketlenecek birim kendine verilen alanın tamamını kaplar.
5. parametre:Belirttiğimiz miktarda bileşenin kenarlarında boşluk bırakır yani tam sayı giriyoruz buralara.

Çok fazla teori oldu... Biraz da örnekler üzerinden gidelim.


#include <gtk/gtk.h>


static void destroy( GtkWidget *widget, gpointer   data )
{
    g_print("Kapatılıyor...\n");
    gtk_main_quit ();
}

int main( int   argc,  char *argv[] )
{
    GtkWidget *Pencere, *YatayKutu, *Dugme1, *Dugme2, *Dugme3;
   
    gtk_init (&argc, &argv);       // Bütük GTK programlarında olacağı gibi fonksiyonumuzu çağırdık

    /// Ana pencere oluşturulup istenilen özellikler ayarlanıyor.
    Pencere = gtk_window_new (GTK_WINDOW_TOPLEVEL);  // Pencere oluşturuluyor
    gtk_window_set_title(GTK_WINDOW(Pencere), "Ana Pencere"); // Pencerenin başlığı ayarlanıyor
    gtk_window_set_position(GTK_WINDOW(Pencere), GTK_WIN_POS_CENTER); // Pencrenin ekranın ortasında açılması sağlanıyor
    gtk_window_set_default_size(GTK_WINDOW(Pencere), 300, 400); // Pencerenin boyutları ayarlanıyor   
    g_signal_connect (Pencere, "destroy",  G_CALLBACK (destroy), NULL); // Penceremizin kapanma olayı

    /// Yatay Kutumuz oluşturuluyor
    YatayKutu = gtk_hbox_new(TRUE, 0);// Bileşenler içerisinde homojen yerleştirilsin (TRUE), birimler arası boşluk olmasın (0)
    gtk_container_add(GTK_CONTAINER(Pencere), YatayKutu); // Pencere içerisine yatay  kutumuzu yerleştiriyoruz.

    //Düğmelerimiz oluşturuluyor
    Dugme1 = gtk_button_new_with_label ("1. Düğme");
    Dugme2 = gtk_button_new_with_label ("2. Düğme");
    Dugme3 = gtk_button_new_with_label ("3. Düğme");

    //Düğmelerimizi paketliyoruz
    gtk_box_pack_start(GTK_BOX(YatayKutu), Dugme1, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(YatayKutu), Dugme2, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(YatayKutu), Dugme3, FALSE, FALSE, 0);   

   
    gtk_widget_show_all(Pencere); // Pencere değişkeninin gösterilmesi sağlanıyor
   
    gtk_main ();
   
    return 0;
}



Bu programıderlediğinizde aşağıdaki gibi bir görüntü alacaksınız.

Resim1



Sadece tek bir harfi değiştirerek ise aşağıdaki gibi bir görüntü alacaksınız....

Resim2



Resim1 ile Resim2 arasındaki tek fark;  yatay kutu yerine dikey kutu oluşturulması... Yani 24. satırdaki hbox'ı vbox yapmanız yeterli... Gördüğünüz gibi birisinde soldan sağa birisinde yukarıdan aşağıya doğru dizilim oluyor.

Bu kullanımlara şunları da ekleyerek son örneğimizi verip geçelim... Siz merak ettiğiniz parametreleri değiştirerek yeni görünümler elde edebilirsiniz:


Resim3


Bu görüntü için paylaştığım kodda tek değişiklik;
YatayKutu = gtk_vbox_new(FALSE, 0);
Satırındadır


Bu görüntüdeki değişiklik sadece hbox -> vbox olarak değiştirildi ve düğme ikinci şu şekilde değiştirildi;

gtk_box_pack_start(GTK_BOX(YatayKutu), Dugme2, FALSE, TRUE, 0);

Sizde parametreler ile oynayarak konuyu daha iyi anlayabilirsiniz. Bütün kutu fonksiyonları için BU bağlantıyı kullanabilirsiniz.

TABLOLAR

Tablolar da bir diğer taşıyıcılarımızdan...  Eklediğimiz birimlerin lokasyonu açısından biraz  daha avantajlı. Konum belirlemde boyutlandırmada tablo hücrelerini koordinatlar gibi kullanıyoruz.

GtkWidget* gtk_table_new  (guint rows,   guint columns,  gboolean homogeneous);


Bu fonksiyon ile tablomuzu oluşturuyoruz. İlk iki parametre birer tam sayı...  İlk parametre ile tablonun satır sayısı ikinci parametre ile de sütun sayısını belirtiyoruz. Son parametre ise tablo hücrelerinin ölçüleri ile alakalı. Eğer TRUE olarak geçilirse tablo hücreleri, en geniş birimi içeren hücreye göre yeniden boyutlandırılır, FALSE geçilirse hücre boyutları korunur.

Tablomuzu oluşturmayı gördük artık içerisine bir şeyler ekleyebiliriz.


void  gtk_table_attach  (GtkTable *table,
                         GtkWidget *child,
                         guint left_attach,
                         guint right_attach,
                         guint top_attach,
                         guint bottom_attach,
                         GtkAttachOptions xoptions,
                         GtkAttachOptions yoptions,
                         guint xpadding,
                         guint ypadding);


Bayağı fazla parametre sayısına sahip. Hemen bakalım;

1. parametre: Birim ekleyeceğimiz tablomuz.
2. parametre: Tabloya ekleyeceğimiz birim.
3. parametre: Eklenecek bileşenin yayılacağı en soldaki hücre
4. parametre: Eklenecek bileşenin yayılacağı en sağdaki hücre
5. parametre: Eklenecek bileşenin yayılacağı en üstteki hücre
6. parametre: Eklenecek bileşenin yayılacağı en alttaki hücre
7. ve 8. parametreler için 3 seçenek girebilirsiniz. Tablo yeniden boyutlandırıldığında tablo içerisine eklenecek birimin durumu için kullanılır

GTK_FILL:    Bu şekilde geçilirse birim bütün hücreyi doldurur
GTK_EXPAND: Bu şekilde geçilirse birim hücrenin ortasında durur
GTK_SHRINK:  Eklenecek birim hücre boyutundan büyükse, birim hücre boyutlarına küçültülür

9. parametre: Birimin sağ ve soldan diğer birimler ile olan boşluğu
10. parametre: Birimin yukarı ve aşağıdan diğer birimler ile olan boşluğu



Bir örnek ile pekişterecek olursak;

#include <gtk/gtk.h>


static void destroy( GtkWidget *widget, gpointer   data )
{
    g_print("Kapatılıyor...\n");
    gtk_main_quit ();
}

int main( int   argc,  char *argv[] )
{
    GtkWidget *Pencere, *Tablo, *Dugme1, *Dugme2, *Dugme3;
   
    gtk_init (&argc, &argv);       // Bütük GTK programlarında olacağı gibi fonksiyonumuzu çağırdık

    /// Ana pencere oluşturulup istenilen özellikler ayarlanıyor.
    Pencere = gtk_window_new (GTK_WINDOW_TOPLEVEL);  // Pencere oluşturuluyor
    gtk_window_set_title(GTK_WINDOW(Pencere), "Ana Pencere"); // Pencerenin başlığı ayarlanıyor
    gtk_window_set_position(GTK_WINDOW(Pencere), GTK_WIN_POS_CENTER); // Pencrenin ekranın ortasında açılması sağlanıyor
    gtk_window_set_default_size(GTK_WINDOW(Pencere), 300, 400); // Pencerenin boyutları ayarlanıyor   
    g_signal_connect (Pencere, "destroy",  G_CALLBACK (destroy), NULL); // Penceremizin kapanma olayı

    /// Tablomuz oluşturuluyor
    Tablo = gtk_table_new  (1, 3, TRUE);// Bileşenler içerisinde homojen yerleştirilsin (TRUE), birimler arası boşluk olmasın (0)
    gtk_container_add(GTK_CONTAINER(Pencere), Tablo); // Pencere içerisine yatay  kutumuzu yerleştiriyoruz.

    //Düğmelerimiz oluşturuluyor
    Dugme1 = gtk_button_new_with_label ("1. Düğme");
    Dugme2 = gtk_button_new_with_label ("2. Düğme");
    Dugme3 = gtk_button_new_with_label ("3. Düğme");

    //Düğmelerimizi paketliyoruz
    gtk_table_attach  (GTK_TABLE(Tablo), Dugme1, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);   
    gtk_table_attach  (GTK_TABLE(Tablo), Dugme2, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
    gtk_table_attach  (GTK_TABLE(Tablo), Dugme3, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
   
    gtk_widget_show_all(Pencere); // Pencere değişkeninin gösterilmesi sağlanıyor
   
    gtk_main ();
   
    return 0;
}



Bütün tablo fonksiyonları için BU bu bağlantıyı kullanabilirsiniz

Not: Bir dikey tablo içine tablo, yatay tablo içerisine dikey tablo gibi varyasyonları kullanabilirsiniz. Hatta biraz gelişmiş program yazmaya başlayınca mutlaka bu şekilce taşıyıcıları iç içe kullanmak zorunda kalacaksınız. Denedikçe ve pratik yaptıkça daha iyi öğreniriz sanırım ben de çok fazla üstünde durmadığım için tam olarak istediğim bir arayüzü doğrudan yapamıyorum şimdilik =)

Not2: Genel bütün her şeyi GtkWidget * olarak tanımlıyorduk. Örneğin bir pencere için de bu türü kullanıyoruz fakat boyutunu değiştireceğimiz zaman fonksiyon (GtkWindow *) türünden bir değişken istiyor. Bir GtkWidget * türümüzü bu fonksiyona gönderdiğimizde uyarı alabiliriz... O nedenle şu şekilde makroları kulanıyoruz;

GTK_WINDOW()
GTK_BUTTON()
GTK_TOGGLE_BUTTON() gibi...

Not3: Başlık biraz uzun oldu, bir yerden sonra kontrolümden çıktı diyebilirim, o nedenle imla hatalarını çok denetleme imkanım olmadı... Bu nedenle eğer bir hata varsa kusura bakmayın.

BİRAZ KOD GÖREYİM

GTK+ Kaynaklar;
İngilizce:

http://www.gtk.org/documentation.html
http://library.gnome.org/devel/gtk-tutorial/stable/

Türkçe (aşağıdaki kaynaklar güncel değildir fakat fonksiyon prototiplerinde %99'u aynıdır, ayni incelemenizde fayda var.)
http://linuxfocus.org/Turkce/May2003/article295.shtml
http://www.linuxfocus.org/Turkce/July2003/article303.shtml

Başlıkta gördüğünüz bir yanlışlık var ise (ki GTK+ konusunda ben de yeni olduğum için bu gayet mümkündür,)başlık altında belirtirseniz düzeltirim ve sevinirim... Kolay gelsin...
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

egcodes

GTK ile ilgili nereden kaynak bulurum diyenlere yapıştırın bu url'yi :D

Eline sağlık Semetey.
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d

sem

".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

risperdal

Güzel bir makale olmuş. Ellerine sağlık.

sem

Teşekkür ederim @risperdal... Umarım başlangıç açısından, öğrenmek isteyen arkadaşlara bir faydası olur...

Sorusu olan arkadaşlar başlık altından dile getirebilirler, bildiğim bir şey oldukça cevaplamaya çalışırım... Kolay gelsin herkese...
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

aktoluna

Ellerine sağlık hocam güzel makale olmuş

blackwidow

Qt ' siz olmaz mı hocam Grafik geliştirme ?

Umarım şart değildir yani farklı bir ortam varsa orada da yazabiliriz belki ?

Amenofis

Gtk C ile yazılabiliyor. Fakat c++ bilginiz varsa kesinlikle Qt.

sem

C++ geliştiricileri GTK+ üzerinde geliştirme yapmak isteyecek olurlarsa GTKMM'i (http://www.gtkmm.org/en/) inceleyebilirler:  
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

-DıLgEş-

Aşkın; gözü kör, kulağı sağır, dili tutuk, aklı kıttır..! Hayır yani bu halde nasıl herkesi madara ediyor onu çözemedim..