GTK+3 click olayı nı class icine alma veya clik

Başlatan SerkanK, 01 Nisan 2015 - 16:16:52

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

SerkanK

tum orneklerde GTK dan bir buttonun sinyal olayı  static bir fonksiyonu cağırıyor
static void on_button_clicked(GtkButton* button, gpointer *parametreler )

arayuz olusturmak icin bir tum kodları bir class altına topladım ama bu kodu class icine alamıyorum C ve C++ cok iyi bilmiyorum
GTK da Butonun click olayının Class icindeki bir foknsiyonu çağırmasını istiyorum  ancak bir yol bulamadım ..
Class icine almak istememin sebebi ise  su struct 'ta olusan hata yuzunden

struct _MenuElement {
    gchar* parentName;
    gchar* name;
    gchar* id;
    _MenuType menuType;

};

struct _MenuList {
    list<_MenuElement>MenuElements;
};

programın bir yerinde _MenuList burada bir liste ulusturuyorum  ve bu listeden addMenuButon fonksiyonu ile bir buton grubu olusturuyorum

bir butona tıkladıgımda bu butonun click olayı yine  addMenuButton fonksiyonunu cağırıyor ve MenuElemets listesinden yeni bir buton grubu olusturuyor

addMenubuton fonksiyonunu Class icinden cagırınca listeye ekledikleri sorunsuz cıkıyor  fakat class dısındaki Static void fonksiyonundan addMenubutton fonksiyonunu cagırınca Bu MenuElements   te ekledikllerim doğru gözükmüyor.

Bu yuzden ya bu  click fonksiyonunu  class icine almam lazım yada Dısarıda olucaksada  MenuElement listesini doğru bir şekilde okumam lazım..

bu click fonksiyonunu  nasıl class icine alabilirim veya

listeleri pointer ile cağrılan callback fonksiyonundan nasıl dogru kullanabilirim ? 




hckr

CALLBACK fonksiyonu için obje fonksiyonuna işaret etmek mümkün gözükmüyor. Ancak sınıf içerisindeki static bir fonksiyona işaret edebilirsin ve parametre olarak ilgili objeyi gönderirsin.

http://stackoverflow.com/a/21479130
Örneğin, yukarıdaki bağlantıdaki cevapta this işaretçisi parametresiyle öncelikle bir static fonksiyona ardından this işaretçisi aracılığıyla da obje fonksiyonuna erişim sağlanmış.

GTK+'yı direkt olarak kullanmak yerine gtkmm'e geçersen tam olarak istediğini elde edebilirsin.

Ancak gtkmm'e geçmek yerine aldığın hatayı yukarıda bahsettiğim gibi çözmek sanırım daha uygun.

Sakıncası yoksa, ilgili kaynak kodunun tamamını paylaşırsan daha iyi yardımcı olunabilir.

SerkanK

#2
Baktım verdiğiniz linke  anlamadım tam olarak ordaki kodu , uygulamaya calıstım ama olmadı

Benim kodlar cok karısık 1 haftadır uğraşıyorum bir sürü şey ekleyip çıkardım koda  o yuzden biraz dağınık

Eklendi
Program calıstırınca constructor kısmında test.xml den aldıgı datadan     list<TMenuElement>MenuElements icine adı ve sahibi olarak yerlestirip ,  Sol taraftaki bir panele buttonlar olusturuyor.  Bu butonun click olayı ile  struct TParameters ile element adını ve elementin menu tipini gonderiyorum.  on_button_clicked olayında ise yapmaya çalıştıgım ama yapamadıgım sey .. list<TMenuElement>MenuElements  listesini dogru okumak .. bunları printf veya cout ile yazdırınca  Xml den kaydettigim dataları dogru gosteremiyorum .. Bu dataları Main fonksiyounundan da dogru gosteremiyorum. ama Clasın icinden bunu yazdırınca dogru gosteriyor. nedeni nedir anlayamadım
Bu nedenden dolayı on_button_clicked olayını ya clasın icine almalıyım yada listeyi class dısından dogru gostemeryi yapmalıyım  ama 1 haftadır bir ton sey denedim olmuyor. aslında C /C++ iyi bilmediğimden kaynalanıyor pointer olayı cok karısık C de bir turlu yapamadım 



#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>

#include <iostream>
#include <string>
#include <list>


#include "pugixml.hpp"



using namespace std;
using namespace pugi;


GError     *error = NULL;

struct TParameters{
    void* thisptr;
    gchar *ElementName;
    int ElementMenutype;
};

typedef enum{
  MENU_TYPE_HOME,
  MENU_TYPE_ALARM,
  MENU_TYPE_FOLDER,
  MENU_TYPE_OBJECT,
  MENU_TYPE_INVALID
} TMenuType;



struct TMenuElement {
    gchar* parentName;
    gchar* name;
    gchar* id;
    TMenuType menuType;

};

struct TMenuList {
    list<TMenuElement>MenuElements;
};


class tGui {
    private:
    TMenuList MenuList;
    bool tguiError;

    GtkBuilder *builder;
    GtkWidget  *mainwindow,*mainframe,*topbarpanel,*leftpanelbar1,*leftpanelbar2, *bbox,*l1bbox,*l2bbox;

    GtkWidget  *topbarHbox;
    GtkWidget  *button;

    GtkWidget *Z1image;

    GtkCssProvider *provider;
    GdkDisplay *display;
    GdkScreen *screen;
    gsize bytes_written, bytes_read;

    string templatefile;
    string cssfile;

public:

    tGui( gchar *templatefile, gchar *cssfile);
    ~tGui();
    bool load_Windows(gchar *filename);
    bool load_Css(gchar *filename);
    bool run_Window();
    void addMenuButton(gchar *root);
    void iaddMenuButton(gchar *root);
    void load_categoryList(gchar *filename);
    void xmlWalk(xml_node parent);
    void GuiShowMenuElement();
    TMenuType GetMenuType(string nodeName);


};


tGui Gui("testwindow.glade","style.css");





static void on_button_clicked(GtkButton* button, gpointer *params ){

   TParameters *parameters =  (TParameters *)params;
   cout << "d On click Menu Type :"<< parameters->ElementMenutype << " , " << parameters->ElementName << endl;


    if (parameters->ElementMenutype==MENU_TYPE_HOME) {
        cout << "Clicked Button Menu Type : HOME" << endl;
    }else if (parameters->ElementMenutype==MENU_TYPE_ALARM) {
        cout << "Clicked Button Menu Type : ALARM" << endl;
    }else if (parameters->ElementMenutype==MENU_TYPE_FOLDER) {
        cout << "Clicked Button Menu Type : FOLDER" << endl;
//        Buradan Gui::AddMenuButon Kodunu çalıştırmam gerekiyor
    }

}


tGui::~tGui(){

}

tGui::tGui( gchar *templatefile, gchar *cssfile){

    tguiError=false;
    gtk_init( NULL, NULL );


   if (load_Windows(templatefile)  == true ){
        this->~tGui();
   }
   if (load_Css(cssfile)  == true ){
        this->~tGui();
   }

}
bool tGui::load_Windows( gchar *filename ){

    builder = gtk_builder_new();
    if( ! gtk_builder_add_from_file( builder, filename, &error ) ){
        g_warning( "%s", error->message );
        g_free( error );
        tguiError = true;
        return true;
    }

    mainwindow = GTK_WIDGET( gtk_builder_get_object( builder, "MainWindow" ) );
    // Windows ta Titlebar'ý kaldýr ve maximize et
    gtk_window_set_decorated (GTK_WINDOW(mainwindow),false);
    gtk_window_maximize (GTK_WINDOW(mainwindow));


    leftpanelbar1 = GTK_WIDGET( gtk_builder_get_object( builder, "LeftPanelBar1" ) );
    l1bbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
    gtk_container_add (GTK_CONTAINER (leftpanelbar1), l1bbox);
    gtk_button_box_set_layout (GTK_BUTTON_BOX (l1bbox), GTK_BUTTONBOX_START);

    leftpanelbar2 = GTK_WIDGET( gtk_builder_get_object( builder, "LeftPanelBar2" ) );
    l2bbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
    gtk_container_add (GTK_CONTAINER (leftpanelbar2), l2bbox);
    gtk_button_box_set_layout (GTK_BUTTON_BOX (l2bbox), GTK_BUTTONBOX_START);

    topbarpanel =GTK_WIDGET( gtk_builder_get_object( builder, "TopBarPanel" ) );


    bbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
    gtk_container_add (GTK_CONTAINER (topbarpanel), bbox);

    gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START);

    button = gtk_button_new_with_label("1");
    gtk_container_add (GTK_CONTAINER (bbox), button);

    button = gtk_button_new_with_label("2");
    gtk_container_add (GTK_CONTAINER (bbox), button);
    button = gtk_button_new_with_label("3");
    gtk_container_add (GTK_CONTAINER (bbox), button);




    button = gtk_button_new_with_label("Exit");
    g_signal_connect_swapped (button, "clicked",G_CALLBACK (gtk_widget_destroy), mainwindow);
    gtk_box_pack_start (GTK_BOX (bbox),button,TRUE, FALSE, 5);
    gtk_button_box_set_child_secondary(GTK_BUTTON_BOX (bbox),button,true);



    load_categoryList("test.xml");
    /* Connect signals */
    gtk_builder_connect_signals( builder, NULL );
    /* Destroy builder, since we don't need it anymore */
    g_object_unref( G_OBJECT( builder ) );



    return false;
}

bool tGui::load_Css(gchar *filename){
    display = gdk_display_get_default ();
    screen = gdk_display_get_default_screen (display);


    provider = gtk_css_provider_new ();
    display = gdk_display_get_default ();
    screen = gdk_display_get_default_screen (display);
    gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

    gtk_css_provider_load_from_path (provider,g_filename_to_utf8(filename, strlen(filename),
                                    &bytes_read, &bytes_written, &error),NULL);

    g_object_unref (provider);
    return false;
}

bool tGui::run_Window(){
    /* Show window. All other widgets are automatically shown by GtkBuilder */
  gtk_widget_show_all(mainwindow);

    /* Start main loop */
    gtk_main();

}



void tGui::xmlWalk(xml_node thisNode){
    TMenuElement AddMenu;



    AddMenu.name=(gchar *)thisNode.attribute("name").value();
    AddMenu.parentName=(gchar*)thisNode.parent().attribute("name").value();
    AddMenu.menuType=GetMenuType(thisNode.name());


    AddMenu.id = (gchar *)thisNode.attribute("id").value();

    MenuList.MenuElements.push_back(AddMenu);

    for(xml_node child = thisNode.first_child(); child; child = child.next_sibling())
    {
        xmlWalk(child);
    }

}



void tGui::addMenuButton(gchar *root){


    for (TMenuElement &element: MenuList.MenuElements){
        cout << "Element Parent :" << element.parentName << "\tElement Name :"<< element.name << endl;
        if ((string)element.parentName == (string)root ) {
            button = gtk_button_new_with_label(element.name);
            gtk_widget_set_name(button,element.id);
            gtk_container_add (GTK_CONTAINER (l2bbox), button);

            TParameters *parameters;
            parameters->ElementMenutype= 2;
            parameters->ElementName="Salon";
            parameters->thisptr= this;

            g_signal_connect( button, "clicked", G_CALLBACK (on_button_clicked),(gpointer)parameters) ;
          }
    }
}




void tGui::iaddMenuButton(gchar *root){

    cout << "--------------------- " << endl;
    list<TMenuElement>::iterator it;
    it = MenuList.MenuElements.begin();
    while (it != MenuList.MenuElements.end()) {
        cout << "Name: " << it->parentName <<"Name: " << it->name  <<endl;
        it++;
    }

    cout << '\n';

}


void tGui::load_categoryList(gchar *filename){
    xml_document doc;
    xml_parse_result result = doc.load_file(filename);
    xmlWalk(doc.child("root"));
    addMenuButton("root");


}



TMenuType tGui::GetMenuType(string nodeName){
    TMenuType type;
    cout << "Select Menu Type :Node Name:"<< nodeName << endl;
    if (nodeName == "home") {
        type=MENU_TYPE_HOME;
    }else if (nodeName == "alarm") {
        type=MENU_TYPE_ALARM;
    }else if (nodeName == "folder") {
        type=MENU_TYPE_FOLDER;
    }else if (nodeName == "object") {
        type=MENU_TYPE_OBJECT;
    }else {
        type=MENU_TYPE_INVALID;
    }
    return type;
}



int main(int argc, char* argv[]){

    Gui.run_Window();

    return 0;
}




Test.xml dosyası

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>

<root name="root" pos="n">
    <home name ="Home" id="Home"></home>

    <alarm name="Alarm" id="Alarm">
        <object id="Object_1" />
    </alarm>


    <folder name="Giris" id="Giris">

        <folder name="AraBolum" id="AraBolum">
            <object name="Object2" id="Object_2" />
            <object name="Object3" id="Object=3" />
        </folder>

    </folder>
</root>


Amenofis

Objeye nereden eriştiğinin bir önemi yok, aynı objeye eriştiğin sürece veriler aynı çıkar. Sen muhtemelen farklı objelere erişiyorsun. Veri doğru çıktığında ve çıkmadığında ilgili objenin adresini yazdırıp karşılaştırma yapabilirsin. Aslında bu olay debug yaparak çok rahat çözülür ama muhtemelen daha önce yapmamışsındır.

Yukarıdaki paragrafı yazdıktan sonra koduna biraz göz gezdirdim ve çok kritik bir hata gördüm, muhtelemen başka hatalar da vardır.

TParameters *parameters;
parameters->ElementMenutype= 2;
...

C++ ta bu şekilde olmaz. parameters işaretçisinin nereyi gösterdiği belli değil. Yani bellekte iznin olmayan yerlere bişeyler yazıyorsun. Zaten yazdığın şeyler sabit, onları silip fonksiyonun başına;
TParameters parameters = {this, "Salon", 2}; eklersen bu hatayı fixlemiş olursun.

İstersen bunu düzelttikten sonra tekrar dene.

SerkanK

ya  C ve C++ iyi bilmiyorum ozellikle su pointer olayını iyi anlamadım. pointerın ne oldugunu ne işe yaradıgını ve nasıl kullanıldıgı ile ilgili mantıgı biliyorum ama C de adamın kafasını karısıtırıyor bu pointer olayı

TParameters *parameters = {this,"Salon",2};
Yapınca  şu hatayı veriyor   error: scalar object 'parameters' requires one element in initializer

TParameters parameters = {this,"Salon",2};
Basındaki * işaretini kaldırınca  bu kodun aldıntaki satır hata veriyor  error: invalid cast from type 'TParameters' to type 'gpointer {aka void*}'|
g_signal_connect( button, "clicked", G_CALLBACK (on_button_clicked),(gpointer)parameters) ;


Amenofis

Tanımlarken * işareti olmayacak. Fonksiyona geçirirken önüne & koyacaksın onu unutmuşuz.

..., (gpointer) &parameters);

SerkanK

#6
Evet yaptım bu sekide . ama yinede ama MenuList Yanlıs gosteriyor
Ya Class icerisinden addMenuButton Fonksiyonunu nasıl , nerden kaçkez cagırısam cagırayım sonuc doğru
Ama Class dısından ornegin Main fonksiyonundan Cagırınca veya Main fonksiyonunda Classın icindeki bir fonksiyonu ordanda addmenu buton fonksiyonunu cagırınca
MenuList Yanlıs Cıkıs veriyor.  Burda Bir pointer falan işlemi falanda yok menulist ile ilgilş

Class icerinde   MenuList.MenuElements.push_back(AddMenu); ile listeye ekleme yapıyorum
Class icerisinde Menu listesini yazdırıyorum (sonuc dogru)
class dısından Menu Listesini yazdırıyorum sonuc yanlıs

struct TMenuList {
    list<TMenuElement>MenuElements;
};



burdaki fonksiyonlar sırayla su sekilde calısıyor .

1 ) Bu Fonksiyon ile XML Fonksiyonu ve ardından MenuListe Gore Butonları ekleyen addMenuButton fonksiyonu calıstırılıyor

void tGui::load_categoryList(gchar *filename){
    xml_document doc;
    xml_parse_result result = doc.load_file(filename);
    xmlWalk(doc.child("root"));
    addMenuButton("root");
}




2 XMLWALK xmlden datayı alıp Menu Liste ekliyorum

void tGui::xmlWalk(xml_node thisNode){
    TMenuElement AddMenu;

    AddMenu.name=(gchar *)thisNode.attribute("name").value();
    AddMenu.parentName=(gchar*)thisNode.parent().attribute("name").value();
    AddMenu.menuType=GetMenuType(thisNode.name());


    AddMenu.id = (gchar *)thisNode.attribute("id").value();

    MenuList.MenuElements.push_back(AddMenu);

    for(xml_node child = thisNode.first_child(); child; child = child.next_sibling())
    {
        xmlWalk(child);
    }

}


3 ) addMenuButton MenuListeki dataya gore buttonları ve isimlerini olusturuyor
void tGui::addMenuButton(gchar *root){
    cout << "Menu List Adress " << &MenuList;
    for (TMenuElement &element: MenuList.MenuElements){
        cout << "Element Parent :" << element.parentName << "\tElement Name :"<< element.name << endl;
        if ((string)element.parentName == (string)root ) {
            button = gtk_button_new_with_label(element.name);
            gtk_widget_set_name(button,element.id);
            gtk_container_add (GTK_CONTAINER (l2bbox), button);

            TParameters parameters = new TParameters({"Salon",2});

            g_signal_connect( button, "clicked", G_CALLBACK (on_button_clicked),(gpointer)&parameters) ;
          }
    }
}


ADRESS TESTI ICIN KODU ASAGIDAKI GIBI YAPTIM
   for (TMenuElement &element: MenuList.MenuElements){

        cout <<"Element Address :" << &MenuList << " --- " << &element << "  Parent :" << element.parentName << "  Name :"<< element.name << endl;

Class icinden cagırınca aynı adresler gozukuyor ve class dısından cağırınca aynı adresler gozukuyor
ama class dısından Bu Liste icine kaydettiklerim gozukmuyor




Amenofis

Maalesef buradan hatayı görmek çok zor. Derleyip bakayım dedim ama eksik dosyalar var.

TParameters parameters = new TParameters({"Salon",2}); // Bu satır yine yanlış.

SerkanK

#8
Evet sizin dediğinizi ilk basta denedim.
TParameters parameters = {this,"Salon",2};
MenuList yanlıs gosterdiği için sonra internetten initilazed ile ilgili arasıtırdım baska seylerde denedim ..sonra  gonderirkende en son denediğim le gonderdim .

Bu arada kodu parca parca denedim   addMenuButton icinde GTK ile ilgili buton olusturan kodları Comment bloguna aldıgım  ozaman MenuList Dısarıdan erişilince dogru gosteriyor. ben bu kodları ekleyince  MenuListe Dısarıdan Erişince MenuList Başka Kodlar Gösteriyor.
 
hckr 'ın gönderği bir link var http://stackoverflow.com/questions/21478803/member-function-as-callback-function-to-g-signal-connect/21479130#21479130 ben bu linkteki kodu pek anlayamadım  2 nolu cevapta onlick olayını class icine almıs ama ben yapmamadım
burda 2 ve 3 un class icinde fonksiyoların kodları yazılmıs  ama 1 kodu yazılmamı ??
birde buton click olayına call back yaparken hangisini kullanıcaz

1 - virtual void on_button_clicked(GtkWidget* button);
2 -  void connect_button_clicked(GtkWidget* button)
3 - static void button_clicked_callback(GtkWidget* button, gpointer* data)


class Window
{
    public:
    virtual void on_button_clicked(GtkWidget* button);

    void connect_button_clicked(GtkWidget* button) {
        g_signal_connect(
            button,
            "clicked",
            G_CALLBACK(button_clicked_callback), this);
    }

    private:
    static void button_clicked_callback(GtkWidget* button, gpointer* data) {
        reinterpret_cast<Window*>(data)->on_button_clicked(button);
    }
};

Amenofis

#9
Sen zaten "Gui" nesneni global alanda tanımlamışsın, yani on_button_clicked fonksiyonu ile o nesnenin "public" üyelerine erişebilirsin. Gui.addMenuButton(...) gibi.

Eğer buton olayı private üyelere erişsin dersen örnekteki gibi static üye fonksiyona bağlantı yapacaksın.

class TGui {
private:
    int prv_member;

public:
    static void on_button_clicked(GtkWidget *button, gpointer data) {
        TGui *thiz = reinterpret_cast<TGui *> (data);
        thiz->prv_member = 0;
        ...
}
};

// Sinyal bağlantısını sınıf içinde yapacaksan eğer;
g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), this);

Dışarıda yapacaksan;
TGui gui(...);
g_signal_connect(button, "clicked", G_CALLBACK(TGui::on_button_clicked), &gui);