FLTK: probleme mit callback-funktion



  • #include <FL/Fl.H>
    #include <FL/Fl_Double_Window.H>
    #include <FL/Fl_Button.H>
    #include <iostream>
    
    class MyWin : public Fl_Window
    {
    	static void Callback_Funct (Fl_Widget *w, void *data)
    	{
    		data++;
    		exit(1);
    	}
    public:
    	int data;
    	MyWin (int w, int h, const char *name = 0) : Fl_Window(w,h,name)
    	{
    		data = 0;
    		Fl_Button *but = new Fl_Button (10,10,30,30,"OK");
    		but->callback(Callback_Funct);
    		end();
    		show();
    	}
    };
    
    int main() 
    {
    	MyWin win(100,100,"Window");
    	return Fl::run();
    }
    

    warum kommt bei diesem code für zeile 10 folgende fehlermeldung:

    C2036: 'void *' : unknown size

    oder meine eigentliche frage lautet: wie bekomme ich ausser 'Fl_Widget *w', 'void *data' noch weitere variablen (wie 'data') in meine callback-funktion, ohne dass ich sie global definieren muss?

    DANKE!
    STICK.



  • data ist ein typloser Pointer. Wenn Du ihn nun inkrementierst, müsste der Compiler die Adresse um die Größe des Datentyps erhöhen, auf den der Pointer zeigt. Der ist hier aber void, also undefiniert. Folglich "kennt" der Compiler keine Größe und meldet Dir das.

    Das hier würde gehen:

    char* ein_string = (char*)data;
    ein_string++;
    

    data wird von fltk genutzt, um skalare Datentypen (char, int, long) direkt und alles andere indirekt (via Pointer) zu übergeben.

    So könnte man zum Beispiel einen Callback für alle Buttons verwenden, und in data die ID des Buttons übergeben.

    enum Buttons {ID_BUTTON1=1,ID_BUTTON2,ID_BUTTON3};
        MyWin (int w, int h, const char *name = 0) : Fl_Window(w,h,name)
        {
            data = 0;
            Fl_Button *but = new Fl_Button (10,10,30,30,"BTN1");
            but->callback(Callback_Funct,(long)ID_BUTTON1);
            Fl_Button *but = new Fl_Button (10,10,30,30,"BTN2");
            but->callback(Callback_Funct,(long)ID_BUTTON2);
            Fl_Button *but = new Fl_Button (10,10,30,30,"BTN3");
            but->callback(Callback_Funct,(long)ID_BUTTON3);
            end();
            show();
        }
    

    In der Callback-Funktion kannst Du data dann entsprechend nutzen.

    static void Callback_Funct (Fl_Widget *w, void *data)
        {
            switch((long)data)
           {
                case ID_BUTTON1:
                     exit(1);
                case ID_BUTTON2:
                     break;
                case ID_BUTTON3:
                     break;
        }
    


  • HI JOEDE.

    danke für die antwort. ich habe deine hinweise mal so in meinen code eingebaut, dass sie mir was nützen. der sieht jetzt so aus:

    class MyWin : public Fl_Window
    {
        static void Callback_Funct (Fl_Widget *w, void *data)
        {
    		int *i;
    		i = (int *)data;
    		exit(1);
        }
    public:
    	int i[5]; 
        MyWin (int w, int h, const char *name = 0) : Fl_Window(w,h,name)
        {
    		int j;
    		for (j=0;j<5;j++) 
    			i[j]=j;
            Fl_Button *but = new Fl_Button (10,10,30,30,"OK");
            but->callback(Callback_Funct,(void *) i);
            end();
            show();
        }
    };
    

    das sieht dann aber so aus, als würde man jeweils nur einen datentyp in die callback-funktionen übergeben können und nicht wie in einer normalen funktion beliebig viele variablen. hab ich das richtig verstanden?

    DANKE.
    STICK.



  • stick_thai schrieb:

    das sieht dann aber so aus, als würde man jeweils nur einen datentyp in die callback-funktionen übergeben können und nicht wie in einer normalen funktion beliebig viele variablen. hab ich das richtig verstanden?

    Ja. Du hast nur (void*) -- also einen Pointer oder alles was dort "reinpasst".

    Ich habe Dein Sample nochmal angepasst. So wäre es korrekt.

    class MyWin : public Fl_Window
    {
        static void Callback_Funct (Fl_Widget *w, void *data)
        {
    		int i = (int)data;
    		cout << "button " << i << "wurde gedrückt" <<endl;
    		exit(1);
        }
    public:
    	int i[5]; 
        MyWin (int w, int h, const char *name = 0) : Fl_Window(w,h,name)
        {
            Fl_Button *but = new Fl_Button (10,10,30,30,"OK");
            but->callback(Callback_Funct,(void *)1);
            Fl_Button *but = new Fl_Button (40,10,30,30,"OK");
            but->callback(Callback_Funct,(void *)2);
            Fl_Button *but = new Fl_Button (70,10,30,30,"OK");
            but->callback(Callback_Funct,(void *)3);
            end();
            show();
        }
    };
    

    Statt einem Pointer auf eine applikationsspezifische Datenstruktur wird einfach ein int in das void* reingepackt. Es ist also kein "Pointer auf int", sondern direkt int. Nicht schön, aber die Entwickler wollen das nicht ändern.



  • Ja, das ist halt der Nachteil eines minimalistischen Designs. Man kann nicht alles haben.



  • Artchi schrieb:

    Ja, das ist halt der Nachteil eines minimalistischen Designs. Man kann nicht alles haben.

    Ja, das stimmt wohl. Da Libraries wie libsig++ nicht ohne Eingriffe in die FLTK-Sourcen arbeiten würden, habe ich mir eine kleine functor-Lösung als Callback-Klasse selbstgebacken. Damit fallen die ätzenden static-Methoden weg. Ein Schnippsel würde dann so aussehen:

    class MainWindow_UI 
    {
    	Fl_Double_Window *theMainWindow;
    	Fl_Button *btn_Menu;
    
    	Fl_SimpleCallback<MainWindow_UI> cb_BtnMenu;
    
        protected:
    	void OnMenu (void *data);
    
    }
    

    btn_Menu muss nicht unbedingt als Attribut in der Klasse enthalten sein. Aber ich habe den Zugriff gebraucht. Ansonsten muss ich leider den Callback explizit definieren. Der eigentliche Callback ist die normale Methode OnMenu(). Was von FLTK noch bleibt, ist der Parameter mit dem "universellen" Typ void*.

    Fl_Double_Window* MainWindow_UI::make_window() 
    {
        btn_Menu = new Fl_Button(18,24,35,25);
        cb_BtnMenu.addCallback(this,&MainWindow_UI::OnMenu,btn_Menu);
    
    }
    

    Beim Erzeugen des Fensters mit der Methode make_window() muss ich nach dem Erzeugen des Buttons nur noch den Callback initialisieren. Für den Functor brauche ich den Pointer auf das Objekt (this) und den Methodenpointer (hier &MainWindow_UI::OnMenu) sowie das Widget selbst.

    Wenn jemand Interesse an der Klasse hat, kann ich sie gerne (unter der LGPL) zur Verfügung stellen.


Anmelden zum Antworten