GTK Button tıklandığında fonksiyona birden fazla argüman gönderme

Başlatan hckr, 07 Kasım 2010 - 10:08:00

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

hckr

Merhaba,
Gtk ile uygulamalar geliştirmeye çalışıyorum.
Ancak bazı sorunlarım var.Bunlardan biri de herhangi bir buton tıklanıldığında fonksiyona yalnızca bir argüman gönderebiliyorum ancak birden fazla argüman göndermeye ihtiyacım var.Bunu nasıl yapabilirim.Daha açıklayıcı olması için:

static void fonksiyonum(GtkWidget *widget,gpointer veri,gpointer veri2)
{
     g_print("%c%c",veri,veri2);
}
int main(.....)
{
.............
g_signal_connect(button,"clicked", G_CALLBACK(fonksiyonum),(gpointer)veri1,(gpointer) veri2); //yapmak istediğim bu ancak (gpointer) veri2 kısmını yazamıyorum
............
}

Yardımlarınız için teşekkürler...

sem

Gönderecekleriniz bu şekilde ayrı bir widget değil de veri ise eğer (ben de widget göndermeye takılmıştım =)), %c, %s, %d gibi scanf() ile elde edilebilecek veriler ise eğer, bunları sprintf() fonksiyonu ile bir dizi içerisine gönderip, diziyi fonksiyona parametre olarak geçerseniz, daha sonra fonksiyon içerisinde dizi içinde bulunan değişkenleri okuyacak bir kod yazabilirsiniz.

örneğin;


char karakter1 = 'a';
char karakter2 = 'b';
int     tamsayi   = 10;
char parametre_dizisi[10];
.........

sprintf(parametre_dizisi,"%c%c%d", karakter1,karakter2,tamsayi);

g_signal_connect(button,"clicked", G_CALLBACK(fonksiyonum),(gpointer)veri1, parametre_dizisi);
.........



Bu şekilde gönderdikten sonra fonksiyonum içerisnde de sprintf()'in tersi işlevine sahip sscanf(); fonksiyonu ile değişkenleri okutmayı deneyebilirsiniz.
".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?

hckr


sem

Ben o sorunu şimdilik şu şekilde çözdüm;

Bana gerekli olan şöyle bir şeydi; mesela 10 button değişkeni varsa (yani 10 widget) parametre olarak sadece hangi tuşa basıldığını anlayacağım bir değişken gönderiyorum. Örneğin "1" gönderilirse anlıyorum ki Button1'e basıldı...

Gönderdiğim fonksiyonda da aynı widgeti kullanabilirsem eğer sorun ortadan kalkmış olacaktı =) Ben de widgetleri global olarak tanıttım. Ya da siz widgeti yerel tanıtıp, diğer %c olarak belirttiğiniz değişkenleri de global olarak tanıtabilirsiniz. Hangisi işinize daha çok yararsa...

Benim çözümüm bu şekilde oldu.
".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?

mrti14

Dostlar sem0900 nın söylediği yöntemi bende denemiştim.İşe yarar yöntem.Ama ben herşeyi global tanımlıyorum.Zaten fonksiyon protopinde sınırsız parametre olunca  ... olur.printf de öle mesala  .Ama gtk da sabit.

sem

Alıntı yapılan: mrti14 - 07 Kasım 2010 - 17:53:58
Dostlar sem0900 nın söylediği yöntemi bende denemiştim.İşe yarar yöntem.Ama ben herşeyi global tanımlıyorum.Zaten fonksiyon protopinde sınırsız parametre olunca  ... olur.printf de öle mesala  .Ama gtk da sabit.

Biraz konuyu açmak, yeni bir şeyler öğrenebilmek ve arkadaşa da daha açık yardımcı olabilmek adına şunlarda bahsedelim isterim;

Herşeyi global tanımlamak da olabilir ama ihtiyaca göre yapmak daha faydalı olacaktır. C kuralları olarak bildiğimiz faaliyet alanı (hatta C değil de programlama kuralı da denebilir) sanıyorum ki GTK+ için de geçerlidir. Bu durumda her şeyi Global yapmak demek; bütün Widget'lerin program sonuna kadar hafızada yer kaplaması demek oluyor gibi duruyor.

(hamzaxx aşağıdaki örnekte, soruna yanıt bulabilirsin!)
Mesela senaryo şu olsun; örneğin bir tane gtk_button olarak tanımlanmış get_widget değişkenimiz olsun diyelim. Bu birimin "clicked" sinyalini aldığımız zaman programın yönleneceği fonksiyonda hamzaxx'in dediği gibi birden fazla değişken kullanam isteyelim. Ben örnek olarak bu fonksiyonda iki tane int türü, bir tane char * türü, ve iki tane de GtkWidget kullanmak istiyorum diyelim (hamzaxx bu kadar değişken işinizi görebilir sanırım =))... Şu şekilde kodlarsam eğer sadece Labeller program sonuna kadar saklanacaktır.

#include "gtk/gtk.h"


static gboolean delete_event( GtkWidget *widget, GdkEvent  *event, gpointer   data )
{
    gtk_main_quit ();
    return FALSE;
}

GtkWidget *Label1, *Label2;


static void beni_cagir( GtkWidget *widget, gpointer   data )
{
   int bir, iki;
   char uc[20];
   char labelimiz[60];

   sscanf((gchar *)data,"%d%d%s", &bir, &iki, uc);

   sprintf(labelimiz,"Birinci: %d ve İkinci: %d", bir, iki);

   gtk_label_set_text( GTK_LABEL(Label1), labelimiz);

   sprintf(labelimiz,"Üçüncü ise:%s", uc);

   gtk_label_set_text( GTK_LABEL(Label2), labelimiz);

}


static void temizle( GtkWidget *widget, gpointer   data )
{
   gtk_label_set_text( GTK_LABEL(Label1), "Ben Label1");
   gtk_label_set_text(GTK_LABEL(Label2), "Ben Label2");
}

int main(int argc, char *argv[])
{
   GtkWidget *Pencere, *DikeyKutu, *Button, *Button2;
   int birinci_parametre = 5;
   int ikinci_parametre = 10;
   char ucuncu_parametre[] = "Bu-bir-denemedir";
   char toplam[60];

   gtk_init(&argc, &argv);

   Pencere = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(Pencere), "Pencere");
   gtk_window_set_default_size(GTK_WINDOW(Pencere), 300, 400);

   g_signal_connect (Pencere, "delete-event", G_CALLBACK (delete_event), NULL);

   Label1 = gtk_label_new("Ben Label1");
   Label2 = gtk_label_new("Ben Label2");

   sprintf(toplam,"%d\n%d\n%s", birinci_parametre, ikinci_parametre, ucuncu_parametre);

   Button = gtk_button_new_with_label("Parametreler");
   g_signal_connect (Button, "clicked", G_CALLBACK (beni_cagir), (gpointer) toplam);


   Button2 = gtk_button_new_with_label("Temizle");
   g_signal_connect (Button2, "clicked", G_CALLBACK (temizle), (gpointer) toplam);

   DikeyKutu = gtk_vbox_new(TRUE, 0);

   gtk_container_add(GTK_CONTAINER(Pencere), DikeyKutu);
   gtk_box_pack_start (GTK_BOX (DikeyKutu), Label1, FALSE, FALSE, 0);
   gtk_box_pack_start (GTK_BOX (DikeyKutu), Label2, FALSE, FALSE, 0);
   gtk_box_pack_start (GTK_BOX (DikeyKutu), Button, FALSE, FALSE, 0);
   gtk_box_pack_start (GTK_BOX (DikeyKutu), Button2, FALSE, FALSE, 0);

   gtk_widget_show_all(Pencere);
   gtk_main();

}



ÖNEMLİ NOT: Bu program basit olduğu için bir fark yaratmayacaktır. Çünkü diğer Widgetler de ana program içerisinde tanımlandığı için program sonlanana kadar faaliyet alanları devam edecektir. Sadece bir fonksiyon için tanımlanacak bir Widget olarak düşünürseniz sorumu daha somut olarak anlayabilirsiniz.



Tabi bu şekilde aslında hamzaxx'in sorusuna tam yanıt vermiş olmuyoruz. Yani bu şekilde işini görebilir ama birden fazla parametre göndermiş olmaz. Program kodlarını incelerseniz fazla parametre göndermeye de örnek var fakat birden fazla parametre ile Widget göndermek yok.

Aslında bunu yapabilmek için çok fazla seçeneğiniz var. Mesela GTK+ türleri de bildiğimiz int, char gibi birer türden başka bir şey değil. Bu ne demek oluyor? Yani siz diyelim ki parametre olarak 10 tane Widget göndermek mi istiyorsunuz. Şöyle bir yol izlenebilir;

GtkWidget *TumWidgetlerim[10];

TumWidgetlerim[0] : Label,
TumWidgetlerim[1]: Button,
TumWidgetlerim[2]: Combobox
TumWidgetlerim[3]: checkbox
TumWidgetlerim[4]: Radiobutton...
.
.
.

Gibi farklı tanımladıktan sonra sonra sadece bu diziyi parametre olarak gönderip, sonra fonksiyon içerisinden istediğiniz bir indise ulaşabilirsiniz. Denemedim bunu, gerek olmadı benim çalışmamda, ama şöyle bir daha baktımda çok da güzel bir yöntem olur gerçekten =)=)=) Denem lazım...



Arkadaşın dediği gibi, fonksiyonlar için o anlık değil de, genel olarak, main() içerisindeki birimleri global tanımlayarak her fonksiyondan istediğinze ulaşabilirsiniz.




void callback_func( GtkWidget *widget,
                    ... /* other signal arguments */
                    gpointer   callback_data );


Bu şekilde tanımlanmış fonksiyonun prototipi... Arada farklı argümanlar tanımlanabilir gibi belirtilmiş. Az önce denedim gerçekten araya bir şeyler sıkıştırdım ve hata ya da uyarı vermiyor. Ama oraya tanımladığım argümana, değişkeni gönderecek olan fonksiyonu bulamadım.
gulong g_signal_connect( gpointer      *object,
                         const gchar   *name,
                         GCallback     func,
                         gpointer      func_data );


Bu fonksiyonun sonuna ekledim ama hata verdi. Fakat biraz araştırıp bulunabilir belki...

hamzaxx, gönderdiğim kodları incelerseniz bir ilk button da 2'si int, birisi char * türünde normal değişkenler, bunlara ek olarak da 2 GtkWidget * türünden birim kullanıyor. İkinci button ise sadece iki tane GtkWidget * türünden değişken ile işlem yapıyor. Yardımı dokunur umarım.




".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?

hckr

Kodlarda nasıl birden fazla değişken gönderdiğini halen anlayabilmiş değilim...
Benim amacım bir widget + bir int göndermek diyelim bunu nasıl yapacağım?


sem

Widget'i Global olarak tanımlayacaksınız. Main Fonksiyonundan önce tanımlayın..

//Widgeti burada tanımlayın

int main....
{
//Bu kod blokları arasında değil
}


Değişken main fonksiyonu ile sınırlanmadığı için, fonkisyona parametre olarak göndermenize gerek kalmaz. Doğrudan fonksiyon içinde de kullanabilirsiniz. Örnek koddaki;

GtkWidget *Label1, *Label2;

Değişkenlerinin nerede tanımlandığında ve fonksiyonlarda nasıl kullandığnı incelerseniz anlayacaksınız demek istediğimi...
".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

C bilmediğim için cevapların çoğunu okumadım ama struct olarak bir değişken tanımlayıp yapabilirsin sanırım.

sem

Alıntı yapılan: risperdal - 14 Kasım 2010 - 19:17:15
C bilmediğim için cevapların çoğunu okumadım ama struct olarak bir değişken tanımlayıp yapabilirsin sanırım.

Çok mantıklı.
".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?

sem

Bir şey daha ekleyeyim; fonksiyon ile bir widgeti gönderiyorsak widget'in faaliyet ömrü demek ki tanımladığımız fonksiyon ile kısıtlı ve parametre olarak gönerdiğimiz fonksiyonun bu alana erişimi yok. Tahminimce widgetleri ana fonksiyon (main) içerisinde tanıtıyorsunuz.

Faaliyet alanını neden kullanıyoruz; değişkenin görevi bittiğinde bellekte yer kaplamasın ve diğer fonksiyonlar içerisinde aynı isimdeki değişkenler nedeni ile karışıklık çıkartmasın gibi sebepler ile...

Ana fonksiyon içerisinde bir widget tanımladığımız zaman;

int main(...)
{
...
GtkWidget *Entry;
GtkEntry = gtk_entry_new();
...
...

gtk_main();
return 0;
}


Bu metin girdisi alan birimin içeriğini diğer fonksiyonlar ile elde edeceğiz diyelim...

Programımızı çalıştırdık diyelim, penceremiz oluştu ve değişken belleğe yerleşti diyelim. Bu değişken zaten program sonlanana kadar bellekte durmayacak mı? Programın akışı biz sonlandırana kadar  "return" ifadesine ulaşamayacak çünkü önünü gtk_main() ile kesmiş bulunuyoruz. Bu durumda değişkenimizi ;

GtkWidget *Entry;
int main(...)
{
...
GtkEntry = gtk_entry_new();
...
...

gtk_main();
return 0;
}


Bu şekilde tanımlamak ile bellek israfı yapmamış oluyoruz çünkü zaten ana program sonlanana kadar orada kalacak. Hem de bütün fonksiyonlardan erişime açıyoruz. Main içerisindeki bütün "widgetleri" bu şekilde tanımladığımızda, bunları fonksiyonlara geçilecek parametrelerden eksiltebiliriz.


Yanlış mı düşünüyorum acaba?
".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?