Advanced Services | draw(), resize() und handle() |
Die Methode draw() zeichnet das Fenster neu, wenn Teile davon verdeckt worden sind oder das Fenster vergößert
oder verkleinert wird. Mit dem folgenden kleinen Programm kann man dieses Verhalten nachvollziehen. Dazu
wird eine Unterklasse MyWindow von Fl_Window erzeugt und die draw()-Methode entsprechend überschrieben.
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl_Window.H> #include <stdio.h> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // draw wird überschrieben void draw(); }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window */ #include "MyWindow.h" void MyWindow::draw() { static int count=0; Fl_Window::draw(); printf("draw called %d\n", ++count); }
main()
/* das beispiel demonstriert den aufruf der draw()-methode dazu wird eine unterklasse MyWindow von Fl_Window erzeugt und die draw()-methode entsprechend überschrieben. auch bei eingaben in Fl_Input wird die draw()-methode gerufen. */ #include <Fl.H> #include <Fl_Window.H> #include <Fl_Widget.h> #include <Fl_Input.H> #include "MyWindow.h" int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "DrawDemo"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); // x=20, y=80, width=150, height=30 Fl_Input *inputField = new Fl_Input(20, 80, 150, 30); inputField->value(" enter text"); win.show(); return Fl::run(); }
Und so sieht das aus:
Die Methode resize() wird natürlich immer dann gerufen wenn sich die Fenstergröße ändert. Sie wird aber auch gerufen
wenn man das Fenster lediglich verschiebt.
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl_Window.H> #include <stdio.h> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // resize wird überschrieben void resize(int x, int y, int w, int h) ; }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window */ #include "MyWindow.h" void MyWindow::resize(int x, int y, int w, int h) { static int count=0; Fl_Window::resize(x, y, w, h); printf("resize called %d\n", ++count); }
main()
/* wie und wann wird resize aufgerufen dazu unterklasse von Fl_Window erstellen und darin die resize-methode überschreiben void resize(int x, int y, int w, int h) { Fl_Window::resize(x, y, w, h); printf("resize called\n"); } wie man natürlich vermuten kann, wird resize bei größenänderungen gerufen es wird aber auch bei reinen move-vorgängen gerufen. */ #include <Fl.H> #include <Fl_Window.H> #include "MyWindow.h" int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "ResizeDemo"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); win.show(); return Fl::run(); }
Und so sieht das aus:
Die zweifelslos interessanteste Methode ist die handle()-Methode. Hier landen nämlich alle Events. Über
den übergebenen int-Wert lassen sich die Events identifizieren. Im ersten Beipiel überschreiben wir die handle()-Methode
und lassen uns nur die Eventnummer ausgeben. Man erkennt Mouseevents, Focusevents und Keyboardevents.
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl_Window.H> #include <stdio.h> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // handle wird überschrieben int handle(int e); }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window */ #include "MyWindow.h" int MyWindow::handle(int e) { static int count=0; printf("event number %d\n", e); return Fl_Window::handle(e); }
main()
/* wie und wann wird handle aufgerufen dazu unterklasse von Fl_Window erstellen und darin die handle-methode überschreiben */ #include <Fl.H> #include <Fl_Window.H> #include "MyWindow.h" int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "HandleDemo"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); win.show(); return Fl::run(); }
Und so sieht das aus:
In diesem Beispiel werden wir die Events genau zuordnen. Anhand der Nummern sind die Events zu unterscheiden.
Man sollte allerdings nie die Zahlen direkt verwenden (keine magic numbers im Programm !) sondern immer die
über define festgelegten Bezeichner. Diese sind in Enumerations.H vereinbart.
Bei Mouseevents erfährt man über die Klassenmethode Fl::event_button() welcher Mousebutton gedrückt wurde.
Die Klassenmethoden Fl::event_x() und Fl::event_y() liefern dann die Koordinaten.
Bei Keyevents liefert int key = Fl::event_key(); die Tastennummer und const char* text = Fl::event_text();
den Buchstaben der gedrückten Taste. Vorsicht, die letzte Methode gibt einen klassischen c-String zurück!
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl.H> #include <Fl_Window.H> #include <stdio.h> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // handle wird überschrieben int handle(int e); }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window behandeln von mouseevents focusevents keyevents das geht natürlich genauso für alle anderen widgets FL_PUSH etc. sind globale konstanten das ist alles vereinbart in Enumerations.H enum Fl_Event { // events FL_NO_EVENT = 0, FL_PUSH = 1, FL_RELEASE = 2, FL_ENTER = 3, FL_LEAVE = 4, FL_DRAG = 5, FL_FOCUS = 6, FL_UNFOCUS = 7, FL_KEYDOWN = 8, FL_KEYUP = 9, FL_CLOSE = 10, FL_MOVE = 11, FL_SHORTCUT = 12, FL_DEACTIVATE = 13, FL_ACTIVATE = 14, FL_HIDE = 15, FL_SHOW = 16, FL_PASTE = 17, FL_SELECTIONCLEAR = 18, FL_MOUSEWHEEL = 19, FL_DND_ENTER = 20, FL_DND_DRAG = 21, FL_DND_LEAVE = 22, FL_DND_RELEASE = 23 }; // Fl::event_button(): #define FL_LEFT_MOUSE 1 #define FL_MIDDLE_MOUSE 2 #define FL_RIGHT_MOUSE 3 */ #include "MyWindow.h" int MyWindow::handle(int e) { static int count=0; printf("event number %d\n", e); switch(e) { // mouse events case FL_PUSH: { int mouseButton = Fl::event_button(); printf("FL_PUSH event number %d\n", e); // 1 printf("mouseButton = %d\n",mouseButton); // 1 = links, 3 = rechts int x = Fl::event_x() ; int y = Fl::event_y(); printf("x = %d\n", x); // koordinaten printf("y = %d\n", y); // koordinaten break; } case FL_RELEASE: printf("FL_RELEASE event number %d\n", e); // 2 break; case FL_DRAG: printf("FL_DRAG event number %d\n", e); // 5 break; case FL_MOVE: printf("FL_MOVE event number %d\n", e); // 11 break; case FL_MOUSEWHEEL: printf("FL_MOUSEWHEEL event number %d\n", e); // 19 break; // focus events case FL_FOCUS: printf("FL_FOCUS event number %d\n", e); // 6 break; case FL_UNFOCUS: printf("FL_UNFOCUS event number %d\n", e); // 7 break; case FL_ENTER: printf("FL_ENTER event number %d\n", e); break; case FL_LEAVE: printf("FL_LEAVE event number %d\n", e); // 4 break; // key events case FL_KEYDOWN: { printf("FL_KEYDOWN event number %d\n", e); // 8 int key = Fl::event_key(); const char* text = Fl::event_text(); printf("key = %d\n", key); // printf("text = %s\n", text); // break; } case FL_KEYUP: printf("FL_KEYUP event number %d\n", e); // 9 break; case FL_SHORTCUT: printf("FL_SHORTCUT event number %d\n", e); // 12 break; } return Fl_Window::handle(e); }
main()
/* wie und wann wird handle aufgerufen dazu unterklasse von Fl_Window erstellen und darin die handle-methode überschreiben */ #include <Fl.H> #include <Fl_Window.H> #include "MyWindow.h" int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "HandleDemo"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); win.show(); return Fl::run(); }
Und so sieht das aus:
In diesem Beispiel werden wir die Behandlung der Events verlagern. Statt in handle() selbst zu reagieren, leiten wir die
Events in die callback()-Methode weiter und reagieren dann in dieser Methode.
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl_Window.H> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // handle wird überschrieben int handle(int e); }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window weiterleiten der events an die callbackfunktion */ #include "MyWindow.h" int MyWindow::handle(int e) { // weiterleitung an die callback()-funktion this->do_callback(this, e); return Fl_Window::handle(e); }
main()
/* wie und wann wird handle aufgerufen dazu unterklasse von Fl_Window erstellen und darin die handle-methode überschreiben events weiterleiten an die callback-funktion */ #include <Fl.H> #include <Fl_Window.H> #include <stdio.h> #include "MyWindow.h" void eventHandler(Fl_Widget* source, long ev); int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "HandleDemo3"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); win.callback(eventHandler); win.show(); return Fl::run(); } void eventHandler(Fl_Widget* source, long e) { //printf("event number %d\n", e); switch(e) { // mouse events case FL_PUSH: { int mouseButton = Fl::event_button(); printf("FL_PUSH event number %d\n", e); // 1 printf("mouseButton = %d\n",mouseButton); // 1 = links, 3 = rechts int x = Fl::event_x() ; int y = Fl::event_y(); printf("x = %d\n", x); // koordinaten printf("y = %d\n", y); // koordinaten break; } case FL_RELEASE: printf("FL_RELEASE event number %d\n", e); // 2 break; case FL_DRAG: printf("FL_DRAG event number %d\n", e); // 5 break; case FL_MOVE: printf("FL_MOVE event number %d\n", e); // 11 break; case FL_MOUSEWHEEL: printf("FL_MOUSEWHEEL event number %d\n", e); // 19 break; // focus events case FL_FOCUS: printf("FL_FOCUS event number %d\n", e); // 6 break; case FL_UNFOCUS: printf("FL_UNFOCUS event number %d\n", e); // 7 break; case FL_ENTER: printf("FL_ENTER event number %d\n", e); break; case FL_LEAVE: printf("FL_LEAVE event number %d\n", e); // 4 break; // key events case FL_KEYDOWN: { printf("FL_KEYDOWN event number %d\n", e); // 8 int key = Fl::event_key(); const char* text = Fl::event_text(); printf("key = %d\n", key); // printf("text = %s\n", text); // break; } case FL_KEYUP: printf("FL_KEYUP event number %d\n", e); // 9 break; case FL_SHORTCUT: printf("FL_SHORTCUT event number %d\n", e); // 12 break; } }
Kleine Anwendung unserer Erkenntnisse
Wir schreiben eine kleine Anwendung, bei der sich eine Komponente automatisch an die größe des Hauptfensters anpaßt.
Dabei kann man sehen wie man von einem Hauptfenster auf die Komponenten zugreift und auch umgekehrt, wie man über
eine Kindkomponente die Elternkomponente erhält.
Erste Variante: Reaktion in der resize()-Methode
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl_Window.H> #include <Fl_Widget.H> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // resize wird überschrieben void resize(int x, int y, int w, int h) ; }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window das hauptfenster ermittelt die (einzige) child-komponente und paßt die größe an */ #include "MyWindow.h" void MyWindow::resize(int x, int y, int w, int h) { Fl_Window::resize(x, y, w, h); // dieses child ist der button ! Fl_Widget* child = this->child(0); child->resize(child->x(), child->y(), this->w(), child->h() ) ; }
main()
/* hier muß nur noch das fenster und der button angelegt werden */ #include <Fl.H> #include <Fl_Window.H> #include <stdio.h> #include "MyWindow.h" int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "ResizeButtonDemo"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); // x=20, y=20, width=150, height=30 Fl_Button *button = new Fl_Button(0, 0, 350, 30, "drück mich"); win.show(); return Fl::run(); }
Zweite Variante: Weiterleitung mit do_callback() und Reaktion in der callback()-Methode
Der Header MyWindow.h
#ifndef _MY_WINDOW_ #define _MY_WINDOW_ #include <Fl_Window.H> #include <Fl_Widget.H> class MyWindow : public Fl_Window { public: MyWindow(int x, int y, int w, int h, const char* poi=0) : Fl_Window(x, y, w, h, poi) { } MyWindow(int w, int h, const char* poi=0) : Fl_Window(w, h, poi) { } MyWindow::~MyWindow() {} // resize wird überschrieben void resize(int x, int y, int w, int h) ; }; #endif // end _MY_WINDOW_
Die Implementierung mywindow.cpp
/* implementierung von MyWindow: public Fl_Window das hauptfenster ermittelt die (einzige) child-komponente und paßt die größe an */ #include "MyWindow.h" void MyWindow::resize(int x, int y, int w, int h) { Fl_Window::resize(x, y, w, h); // weiterleiten this->do_callback(); }
main()
/* hier muß jetzt die größenanpassung in der callback()-methode stattfinden */ #include <Fl.H> #include <Fl_Window.H> #include <stdio.h> #include "MyWindow.h" void winAction(Fl_Widget* o, void* b); int main() { //x = 300, y = 300 relative zum screen MyWindow win(300,300,350,250, "ResizeButtonDemo"); win.size_range(150,100); // minimale größe // durch diese angabe wird das fenster resizable Fl_Color col = fl_rgb_color(200,220,240); //hintergrundfarbe setzen win.color(col); // x=20, y=20, width=150, height=30 Fl_Button *button = new Fl_Button(0, 0, 350, 30, "drück mich"); // die methode callback wird zu win gerufen, ein pointer auf den button wird übergeben win.callback(winAction, button); win.show(); return Fl::run(); } void winAction(Fl_Widget* o, void* b) { int e = Fl::event() ; //printf("winaction event = %d\n", e); // b ist ein pointer auf den button Fl_Button *butt = (Fl_Button*)b; // so bekommt man die parentkonponente Fl_Window *win = butt->window(); // buttongröße anpassen butt->resize(butt->x(), butt->y(), win->w(), butt->h() ) ; // beendet die anwendung if( e == FL_CLOSE) exit(0); }
Und so sieht das aus: