FLTK: Mehrere Pointer an eine Funktion übergeben



  • Ich befasse mich erst seit kurzem mit FLTK und habe eine Frage. Ich haber ein Fenster erstellt mit folgendem Code:

    #include <FL/Fl.H>
    #include <FL/Fl_Window.H>
    #include <FL/Fl_Button.H>
    using namespace std;
    
    void function1(Fl_Widget* w, void* v)
    {
     Fl_Button* but2 = (Fl_Button*)v;
     Fl_Button* but = (Fl_Button*)w;
     but2->label("JUHU!"); 
     but->label("Click me");
     }
    
    void function2(Fl_Widget* w, void* v)
    {
     Fl_Button* but2 = (Fl_Button*)w;
     Fl_Button* but = (Fl_Button*)v;
     but2->label("Click me!"); 
     but->label("JUHU!");
     }
    
    void resetfunc(Fl_Widget* w, void* v)
    {
    'Hier muss reinkommen, dass die Labels von beiden buttons auf Clickme gesetzt werden 
    }
    
    int main()
    {
        Fl_Window* win = new Fl_Window(200,100, "Hallo Welt");
        win->begin();
                     Fl_Button* but = new Fl_Button(10,10,80,30,"Click me!");
                     Fl_Button* but2 = new Fl_Button(10,50,80,30,"Click me!");
                     Fl_Button* reset = new Fl_Button(100,30,80,30,"Reset");
                     but->callback(function1,but2);
                     but2->callback(function2,but);
                     reset->callback(resetfunc,?);
        win->end();
        win->show();
    
        return Fl::run();
    }
    

    Wie kann ich die Labels von mehreren Buttons, Textfeldern, usw. an eine Funktion übergeben? Es kann doch nicht sein, dass immer nur zwei "Objekte" (falsche terminologie?) mit einander interagieren können, oder?



  • Wo ist das Problem?

    void resetfunc(Fl_Widget* w, void* v)
    {
       but2->label("Click me");
       but->label("Click me");
    }
    


  • aber ich kann doch in einer funktion nur auf "objekte" zugreifen, deren pointer ich auch an besagte funktion übergeben habe, oder?

    wie muss denn bei deiner Version der callback vom resettbutton aussehen?



  • Bei Artchis Version sind die Variablen entweder global oder in einer Klasse gekapselt. Ich kenne mich zwar mit FLTK kein bisschen aus, aber das wird es wohl schon noch können 😉



  • ARGH! OK, hast deine Callback-Funktionen ja garnicht in einer Klasse drin! Warum eigentlich nicht? Ich bin dermassen in objektorientierten Denkweise gegangen, das ich davon ausging, das deine Funktion in einer Klasse steckt, wo wiederrum die beiden Buttons drin sind und du diese dann natürlich nicht mehr übergeben müsstest. So sollte es eigentlich auch sein.

    Wenn du diese nur per Parameterübergabe bekommen kannst, mußt du dir halt etwas bauen. Z.B. eine Struct:

    struct beide_buttons
    {
       Fl_Button* but;
       Fl_Button* but2;
    };
    

    Und dann:

    beide_buttons *beide = new beide_buttons;
    beide->but = but;
    beide->but = but2;
    
    reset->callback(resetfunc, beide);
    

    Dann kannste die in deiner Funktion benutzen:

    void resetfunc(Fl_Widget* w, void* v)
    {
       beide_buttons *beide = (beide_buttons*) v;
       beide->but2->label("Click me");
       beide->but->label("Click me");
    }
    

    Aber ganz ehrlich? Dein bisheriges Konzept ohne Klassen ist nicht gut.
    Kann man keine Methoden als Callbacks angeben? Mußt du mal in die FLTK-Doku oder so schauen. Mit Funktionen als Callbacks ist es nicht so toll, wie man sieht.



  • In dem grauen Kasten steht, wie man über einen kleinen Workaround Methoden benutzen kann:
    http://www.fltk.org/doc-1.1/common.html#4_9
    Dann kannste das endlich mal vernünftig machen. 😉



  • http://www.anonymouse.ru/cgi-bin/nph-proxy_ru.cgi/000110A/http/br.geocities.com/lipemreis/fltkcb.html

    damit kannst du auch memberfunktionen als callback setzen ohne den blöden workaround.



  • dann werd ich ich wohl nochn bisschen mehr mit klassen rumschlagen 🙂 Danke für eure Hilfe



  • Kann mir villeicht jmd. ein kleines Beispiel für ein auf Klassen basierendes Fenster posten? In diesem tutorial http://www3.telus.net/public/robark/ ist zwar eins drin, aber es ist leider ein bisschen unübersichtlich. Es würde mir schon reichen einfach nur ein Fenster mit einem Knopf angezeigt zu bekommen. Den Rest kann ich mir selbst herleiten.



  • class SimpleWindow : public Fl_Window
    { 
     public:
      SimpleWindow(int w, int h, const char* title) : Fl_Window(w,h,title)
      {
         quit = new Fl_Button();
    
         // hier noch den Callback mit resetfunc verbinden, wie oben in dem Workaround gepostet...
      }
    
      void resetfunc(Fl_Widget* w, void* v)
      {
       quit->label("Click me");  // quit ist ein Member von SimpleWindow
      }
    }
    
     private:
      Fl_Button* quit;
    };
    

    Einfach dein Fenster von Fl-Window ableiten und die Widgets als private Members darin ablegen. So kannst du immer von deinem Fenster aus direkt drauf zugreifen.



  • also ist die main funktion nur noch da um die einzelnen klassen zu steuern?

    was macht in dieser zeile class SimpleWindow : public Fl_Window

    das : public Fl_Window

    sowie das : Fl_Window(w,h,title) hinter der funktion

    bis jetzt habe ich nur mit klassen gearbeitet bei denen zb nur

    class auto

    in der ersten zeile stand

    und deren funktionen wie zb.

    string setname(name)

    aussahen

    außerdem bekomme ich leider einen felher:
    C:\...\p5\Unbenannt1.cpp `quit' undeclared (first use this function)
    wenn ich deine klasse 1:1 übernehme



  • ich beutze dev c++ v 4.9.9.2 mit mingw

    außerdem sehe ich grade, dass der obere fehler durch eine ganze liste weiterer fehler ergänzt wird

    was machen?



  • alfonsospringer schrieb:

    also ist die main funktion nur noch da um die einzelnen klassen zu steuern?

    Eine main-Funktion kann für alles missbraucht werden. Aber ich mache es so, das sie hauptsächlich etwas anstösst. Z.B: ein Hauptfenster erzeugt.

    alfonsospringer schrieb:

    was macht in dieser zeile class SimpleWindow : public Fl_Window

    das : public Fl_Window

    sowie das : Fl_Window(w,h,title) hinter der funktion

    bis jetzt habe ich nur mit klassen gearbeitet bei denen zb nur

    class auto

    in der ersten zeile stand

    und deren funktionen wie zb.

    string setname(name)

    aussahen

    Du kannst noch kein C++ bzw. noch nicht die wichtigsten C++-Sachen bzgl. Objektorientierung. Hast du kein C++-Lehrbuch? Sowas sollte man haben.

    Bei dem : Fl_Window(w,h,title) im Konstruktor (Ctor) handelt es sich um eine Initializer-List. In dem Fall wird der Ctor von Fl_Window initialisiert, weil du von der entsprechenden Klasse abgeleitet hast.

    Du solltest dich etwas genauer mit dem Thema beschäftigen. Das sind Basics die du spätestens jetzt braucht. 😉

    alfonsospringer schrieb:

    außerdem bekomme ich leider einen felher:
    C:\...\p5\Unbenannt1.cpp `quit' undeclared (first use this function)
    wenn ich deine klasse 1:1 übernehme

    Das er quit nicht findet, finde ich merkwürdig. Kann dein Compiler anscheinend nicht, wenn es weiter unten steht. Dann schieb die Member-Variable halt nach oben. Sind doch ganz einfache logische Lösungen, oder?

    Und das du die Klasse 1:1 übernommen hast, ist ja i.O. Aber du hast selber gesagt, das du nur einen Denkanstoss brauchst und es dann selbst zu recht schiebst. 😉



  • Nein, ich habe kein Lehrbuch und ja, ich habe mich noch kaum mit Objektorientierung befasst und meine C++ Programme größtenteils prozedural aufgebaut. Als "Lehrbuch" habe ich bis jetzt Volkards alte und neue c++ Kursr missbraucht, und da wurden die Funktionen nur ohne Initializer-List erstellt.
    Kannstde mal erklären wozu genau die dient und wie er funktioniert? Oder würde das ein Roman werden ?



  • Sehr schade das Leute nicht in ein Lehrbuch investieren. 😞 In der Zeit wo du hier auf Antworten wartest, hättest du es schon längst nachlesen können. Und ein Lehrbuch will ich auch nicht ersetzen (und andere anscheinend auch nicht, wie du an der Antwort-Statistik hier siehst).

    Deshalb ein Link zu einem Lehrbuch, das ich empfehlen kann:
    http://www.hanser.de/buch.asp?isbn=978-3-446-41023-7&area=Computer

    Wenn es trotzdem kein Buch sein soll, dann wenigstens ein vernünftiges Online-Tutorial:
    http://tutorial.schornboeck.net/inhalt.htm
    Initializer:
    http://tutorial.schornboeck.net/initliste.htm
    Wobei alle dieses Tutorials nicht ein komplettes Lehrbuch ersetzen können und es auch nicht in geringster Weise tun.



  • Ich bedanke mich vielmals für deine Hilfe und hoffe das ich nicht allzusehr nerve.
    Ich stimme dir zu, dasss das Buch sehr gut aussieht jedoch liegt es mit seinen stattlichen 40 E leider ausserhalb des von mir angestrebten Rahmens. Vielen dank auch für den Link zu dem Tutorial.

    Ich entschuldige mich nochmal vielmals falls sich irgendwer sehr über meine "Anfängerfragen" geärgert hat.



  • Anfängerfragen werden hier gerne beantwortet. Aber man kann halt nicht von den Forenmitgliedern verlangen, das sie einem das Lesen ersetzen. Wenn es spezielle (Verständnis-)Probleme gibt, wird gerne geholfen.



  • Wunderbar - Ich habe jetzt das Tutorial weitgehend durchegearbeitet und ich habe mal wieder eine Frage:

    Ich wollte es ja schaffen mehrere Buttons,etc an eine Funktion zu übergeben, also habe ich versucht die Callbackfunktion so umzuschreiben, dass ich erstmal einen Button verändern kann ohne dafür seinen Pointer per callback an die Funktion zu übergeben. (müsste doch ganz einfach sein, weil ich innerhalb der Klasse ja uneingeschränkten zugriff auf den Fl_Button* but habe und ihn deswegen doch mmn. auch von der Callbackfunktion aus benutzen können müsste ohne ihn vorher zu übergeben)

    #include <FL/Fl.H>
    #include <FL/Fl_Window.H>
    #include <FL/Fl_Button.H>
    using namespace std;
    
    class SimpleWindow : public Fl_Window{
    
       public:
          SimpleWindow(int w, int h, const char* title );
          Fl_Button* but;
    
       private:
       static void cb_but(Fl_Widget*w, void*)
       {
              but->label("Hallo");
              };
    
    };
    
    int main (){
    
       SimpleWindow win(300,200,"SimpleWindow");
       return Fl::run();
    }
    
    SimpleWindow::SimpleWindow(int w, int h, const char* title):Fl_Window(w,h,title)
    {
    
       begin();
    
          but = new Fl_Button(100, 150, 70, 30, "&ClickMe");
          but->callback(cb_but);
    
       end();
    
       show();
    }
    

    Dies bewirkt einen Fehler:
    invalid use of member `SimpleWindow::but' in static member function

    ich verstehe nicht warum der Zugriff auf but invalid sein soll. Ich greife doch von innerhalb der Klasse daruf zu. Wo liegt der große Fehler in meinem Gedankengang?



  • Ja, du sagst es ja selber: du greift auf die Klassen-Elemente zu! Aber du mußt auf die Objekt-Elemente zugreifen. Klasse != Objekt.

    Deine cb_-Funktion ist static und somit hat sie keinen Zugriff auf ein spezielles Objekt. Klar? Weil static einmalig vorhanden ist, und nicht pro Objekt.

    Du solltest die cb_-Funktion nicht-static machen! Aber dafür brauchst du den von mir genannten Workaround!



  • Ok - jetzt versteh ichs ! Vielen dank für den (zugegeben großen) Erkläraufwand


Anmelden zum Antworten