[X] Einführung in wxWidgets
-
1 Vorbemerkungen
wxWidgets ist ein recht grosses und zu Teilen komplexes
Framework, welches ähnlich wie MFC oder QT versucht alle
Bedürfnisse des Anwendungsentwicklers innerhalb des Frameworks
gerecht zu werden.
wxWidgets verzichtet aber weitgehend auf das Zeichnen eigener Controls,
sondern versucht die nativen Widgets eines Betriebs/Desktopsystems (Win32/WinApi,GTK+ 1/2, Xlib)
zu wrappen, und ermöglicht damit das Schreiben plattformunabhängiger Programme,
welche möglichst das Look & Feel der jeweiligen Plattform bieten.1.1 Unterstütze Plattformen
wxWidgets unterstützt folgende Plattformen:
- wxMSW: Win32/Win64/WinCE.
- wxGTK: GTK+ 1 or 2 on Unix.
- wxX11: Xlib on Unix.
- wxMac: MacOS X/Carbon, MacOS Classic.
- wxMGL: MGL on DOS, Linux and other platforms supported by MGL.
- wxBase: non-GUI builds of the library.
- wxCocoa: MacOS X/Cocoa (beta).
- wxOS2: a Presentation Manager port (alpha).
- wxPalmOS: a Palm OS port (alpha).
Quelle: wxwidgets.org
2 Die Library
Die aktuelle Version von wxWidgets kennt (leider) keine Namespaces, so
das alle Klassen die zur Library gehören mit dem Präfix wx anfangen.
Vieler dieser Klassen verfügen über eine Onlinedokumentation,
so das man sich dort auch einen ganz guten Überblick über die Library verschaffen kann.2.1 Die Library bauen
Es besteht die Option wxWidgets als eine große Library zu bauen (MONOLITHIC) oder
jeweils für die verschiedenen Teile des Frameworks eine eigene Lib zu erhalten.
Die Libraries können als DLL oder als static Libs erstellt werden.
wxWidgets lässt sich mit vielen Compilern übersetzen, z.b. GCC, MSVS 2005 oder MSVC6.0.
Für die Microsoft IDE ist schon einige entsprechende Projektdateien zum bauen von
wxWidgets vorhanden, diese finden sich unter %wxDir%/build/msw/.
Desweiteren findet sich im wxWidgets Hauptverzeichnis auch eine Hilfedatei für
das bauen unter Windows ("INSTALL-MSW.txt"). Wer (wie ich) die GCC verwendet,
sollte um die Library zu bauen MSYS von der MinGW Webseite herunterladen und installieren.
Damit lässt sich wxWidgets recht einfach und schnell bauen, und wer später unter
Linux das selbe tun muss, kennt den Vorgang bereits.
Nach der Installation einfach MSYS starten und ins wxWidgets Verzeichnis wechseln.
Es ist zu empfehlen für den Buildprozess ein eigenes Unterverzeichnis zu erstellen,
auch um bei Fehlern dies einfach wieder löschen zu können.
In der MSYS-Konsole folgende Befehle eintippen:cd $WXWIN # ins wxWidgets verzeichnis wechseln mkdir build-debug # Build-Verzeichnis anlegen cd build-debug # in das Build-Verzeichnis wechseln ../configure --with-msw --enable-debug --enable-debug_gdb --disable-shared # configure mit den entsprechenden parametern ausführen. enable lässt sich durch disable ersetzen, wenn man z.b. keinen debugbuild machen möchte make # startet das eigentliche bauen der Library make install % This step is optional, see note (8) below. cd samples/minimal # wchseln ins sample-Verzeichnis, um einen Testbuild zu machen make # minimal-Beispiel bauen lassen ./minimal.exe # ausführen, wenns geklappt hat, müsste jetzt ein Fenster erscheinen
Quelle: INSTALL-MSW.txt
2.1.1 wxWidgets und die IDEs
Wenn man die Library erfolgreich gebaut hat, und das minimal Beispiel läuft,
muss man wxWidgets noch entsprechend für seine IDE einrichten, wie man dies
für jede andere Library auch muss. Dazu muss man bei den Compileroptionen
die entsprechenden Pfade angeben, für include, und für lib. Dann findet
die IDE in der Regel die Dateien, nicht zu vergessen, das man natürlich die
entsprechenden Libs in seinem Projekt auch noch angeben muss.2.2 wxPack
Wer sich den Aufwand sparen will die Library selbst zu kompilieren, sollte sich wxPack anschauen.
wxPack enthält wxWidgets + die fertigen Libraries für den MingW (gcc 3.4.5) und den MSVC (7.1),
sowie weitere Programme für wxWidgets, wie einen RAD Editor. Für Visual Studio gibt
es sogar einen Installer, welcher wxWidgets für VS installiert.3 Hello World!
Um einen Eindruck von wxWidgets zu bekommen, habe ich ein kleines Hello World Programm geschrieben,
welches einen Button besitzt, und eine TextCtrl. Wenn man auf den Button klickt,
bekommt man einen Eingabedialog, in den man Text eingeben kann, welcher dann an
den Inhalt des TextCtrl angehängt wird.Das Helloworld Programm besteht gerade mal aus 2 Klassen:
MyApp - Eine Applikationklasse, welche u.a. auch den Einstiegspunkt für die main Funktion liefert.
MyFrame - Das eigentliche Hauptfenster, welches in der MyApp erstellt wird, und in der OnInit den Focus bekommt.Dies geschieht in der MyApp::OnInit:
// dieses Makro sorgt für die korrekte Implementierung von MyApp IMPLEMENT_APP(MyApp); bool MyApp::OnInit() { //erstellen der MyFrame Instanz: MyFrame* frame = new MyFrame(0L, _("wxWidgets Hello World")); //Mit Show startet das Hauptfenster frame->Show(); return true; }
Die MyFrame-Klasse ist dann schon etwas komplexer:
#include "app.h" // wx Includes #include <wx/button.h> #include <wx/textctrl.h> // Die Frameklasse für das Hauptfenster sollte immer von wxFrame oder einem seiner "Kinder" abgeleitet sein. class MyFrame: public wxFrame { public: // MyFrame Konstruktor MyFrame(wxFrame *frame, const wxString& title); ~MyFrame(); private: // Ein paar Steuerelmente, damit unser Fenster nicht ganz so leer ist: wxButton* button; wxTextCtrl* txtctrl; // plus einige EventHandler void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); void OnInsertText(wxCommandEvent& event); // Dieses Makro definiert den EventTable für MyFrame. DECLARE_EVENT_TABLE() };
Die Events lassen sich dann entsprechend im EventTable definieren:
// wxEvent Table - Hier können EventMakros eingetragen werden BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(idMenuQuit, MyFrame::OnQuit) EVT_MENU(idMenuAbout, MyFrame::OnAbout) END_EVENT_TABLE()
In wxWidgets gibt es eine Vielzahl an Eventmakros, ähnlich wie in der MFC.
Man kann allerdings auch jeden Event manuell an ein Menu/Steuerelement binden, und auch wieder lösen.
Dies ist allerdings etwas komplizierter als ein EventMakro:Connect(button->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MyFrame::OnInsertText));
- Das erste Argument ist die Id an den der event geschickt werden soll, dies kann (wie hier)
die ID eines Steuerelmentes sein, aber auch z.b. aus einem Enum stammen. - Das zweite Argument ist die ID des Events, welcher verbunden werden soll.
- Das 3. Argument ist der EventHandler, hier gibt es verschiedene (wxMouseEventHandler,wxCommandEventHandler etc.)
Als Argument nimmt dieser Handler die Methode die bei diesem Event aufgerufen werden soll.
Aber bevor man irgendwelche Events an die Steuerelemente binden kann, muss man diese
erstmal erzeugen. Dies geschieht in wxWidgets i.d.R. im Konstruktor, bzw. in einer
Methode die dann von den verschiedenen Konstruktoren aufgerufen wird("CreateGUIControls").
wxWidgets bietet die Möglichkeit, seine Steuerelmente nach Position auszurichten,
wie man dies in der MFC auch machen kann.
Allerdings bietet wxWidgets auch die Möglichkeit, Sizer zu benutzen, welche die
Positionisierung der Steuerelemente dann automatisch übernehmen, und auch an evtl.
Größenveränderungen anpassen. Deswegen ist es sehr empfehlenswert diese Sizer zu benutzen.
Der MyFrame-Konstruktor sieht dann so aus:MyFrame::MyFrame(wxFrame *frame, const wxString& title) : wxFrame(frame, -1, title) { #if wxUSE_MENUS // diese Zeilen erstellen das Menü: // wxMenuBar ist die eigentliche Menükomponente, welche auch später im Programm angezeigt wird... wxMenuBar* mbar = new wxMenuBar(); // wxMenu stellt dann ein Menu in diesem MenuBar da. wxMenu* fileMenu = new wxMenu(_T("")); // mit Append wird ein Menüeintrag erstellt, die ID wurde oben schon im EventTable mit OnQuit verbunden. fileMenu->Append(idMenuQuit, _("&Quit\tAlt-F4"), _("Quit the application")); // das Menü in den Menubar einhängen. mbar->Append(fileMenu, _("&File")); wxMenu* helpMenu = new wxMenu(_T("")); helpMenu->Append(idMenuAbout, _("&About\tF1"), _("Show info about this application")); mbar->Append(helpMenu, _("&Help")); // das Menü dem Fenster übergeben SetMenuBar(mbar); #endif // wxUSE_MENUS // Hier wird nun der eigentliche Fensterinhalt erstellt // Der Sizer wird als erstes erstellt, weil er später die Childfenster von MyFrame aufnimmt. // Die 4 Argumente sind Zeilen, Spalten, vertical gap und horizontal gap. wxFlexGridSizer* sizer = new wxFlexGridSizer(2,1,0,0); // Eine Besonderheit gibt es bei wxFlexGridSizer, man kann angeben, welche Spalten oder Zeilen bei einer Grössenänderung wachsen/schrumpfen sollen. sizer->AddGrowableCol(0); sizer->AddGrowableRow(1); // Anlegen des wxButtons: // Das erste Argument ist das Parent-Fenster: wxWindow* parent // Das zweite Argument ist die ID des Steuerelementes: int id // wxNewId() ist ein Makro welches die nächste gültige ID zurück gibt, // alternativ kann man hier auch einen Wert aus einem Enum oder eine einfache Int variable angeben. // Das dritte Argument ist die Beschriftung des Buttons. button = new wxButton(this,wxNewId(),_("Append Text")); // Nach der Erzeugung wird den Button dem Sizer übergeben. sizer->Add(button, 0, wxALL, 5); // Anlegen des wxTextCtrls: // Erstes Argument ist wieder das Parent, das zweite die ID. // -1 heisst hier, das es keine Event ID innerhalb von wxWidgets braucht, // da keine Eventbindung (EventTable/Connect) vorliegt. Dies kann auch z.b. ID_DEFAULT sein, welches i.d.R. ein #define ID_DEFAULT -1 ist. txtctrl = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE); // Das TextCtrl dem Sizer hinzufügen, die Argumente sind hierbei: // Als erstes das Steuerelement selber. // Das dritte Argument sind die Sizerflags, welche das Verhalten des Steuerelmentes bei Grössenveränderungen abbildet. // wxALL stellt sicher das zu allen Seiten ein Abstand von 5 Pixeln vorhanden ist (4. Argument) // wxEXPAND - Das Steuerelement passt sich den Grössenverändungen des Fensters an sizer->Add(txtctrl,0,wxALL|wxEXPAND, 5); // Sizer dem Hauptfenster übergeben. SetSizer(sizer); // korrektes Layout berechnen Layout(); // Das Fenster bekommt eine Mindestgrösse SetMinSize(wxSize(300,200)); // Fit stellt sicher das alle Steuerelmente ins Fenster passen, und pass notfalls diese an. Fit(); // Mit Connect wird der Button-Click-Event mit der Methode OnInsertText verbunden, mit button als Event Sender. Connect(button->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MyFrame::OnInsertText)); #if wxUSE_STATUSBAR // create a status bar with some information about the used wxWidgets version CreateStatusBar(2); SetStatusText(_("Hello Code::Blocks user !"),0); SetStatusText(wxbuildinfo(short_f),1); #endif // wxUSE_STATUSBAR }
Eine Besonderheit von wxWidgets ist es, das alle Komponenten die zu wxWidgets gehören,
und mit new erzeugt werden, von wxWidgets wieder gelöscht werden, wenn man sie
an wxWidgets übergibt. Daher ist der Destruktor der MyFrame Klasse auch leer.Im Konstruktor wurde der Button-Event mit Connect an die Methode OnInsertText gebunden:
void MyFrame::OnInsertText(wxCommandEvent& event) { // wxTextEntryDialog dient dazu eine Textzeile vom User abzufragen: wxTextEntryDialog dlg(this,_("enter some text"),_("enter some text"),_("")); // ShowModal gibt bei Erfolg wxID_OK zurück if(dlg.ShowModal() == wxID_OK)// AppendText fügt den Text in das TextCtrl ein. "\n" ist für den Zeilenumbruch. txtctrl->AppendText(dlg.GetValue()+"\n"); }
Der gesamte Code des Hello World Beispiels kann hier runtergeladen werden: wxHelloWorld
Weitere Links zum Thema wxWidgest:
http://www.wxwidgets.org
Die offizielle wxWidgets Klassenliste (englisch)
Das offizielle wxWidgets Forum (englisch)
-
So, ich geb das Thema jetzt mal frei, ist schon spät,
daher geh ich davon aus, das das ein oder andere wohl noch nicht
zu 100% fertig ist, muss ich morgen selber mal sehen,
was ich heute Nacht da verzapft hab
-
Hallo,
bitte keine zwei Kürzel im Betreff, hab's mal wieder auf F gesetzt, da du ja noch was ändern wolltest
GPC
-
So, hab noch mal alles durchgelesen, ein paar Änderungen gemacht, und freue mich jetzt auf euer Feedback
-
Hallo,
Es wäre vielleicht noch schön, wenn du etwas über Messageboxen oder Menüs schreiben würdest.
Wieviele Teile stellst du dir über wxWidgets vor?
MFG winexec*
-
Hi,
aus Abschnitt 1:
wxWidgets verzichtet aber weitgehend auf das Zeichnen eigener Controls,
sondern versucht die nativen Widgets eines Betriebs/Desktopsystems (Windows,GTK)hier würde ich die Wahl der verwendeten Widgets etwas präziser beschreiben, also WinAPI unter Windows, unter *BSD, Linux usw. das gtk+ ...
Außerdem schreibst du immer 'gcc'. 'Der gcc' ist aber der C-Compiler, die korrekte Bezeichnung (also der Oberbegriff) ist 'die GCC'. Entweder du benutzt diesen Begriff, oder führst direkt den g++ an, da wxWidgets ja eh 'n C++ Framework ist.
Der Rest liest sich sehr gut und ist detailiert erklärt
Grüße
GPC
-
winexec* schrieb:
Hallo,
Es wäre vielleicht noch schön, wenn du etwas über Messageboxen oder Menüs schreiben würdest.
Wieviele Teile stellst du dir über wxWidgets vor?
MFG winexec*
Also geplant hab ich da noch nix. Mal schauen, Teil 2. hab ich schon was im
Kopf, evtl. eine kleine Anwendung, in der man sieht wie man eigene Controls etc.
in wxWidgets einsetzt, wie die Sizer genau funktionieren, Mouse/Paint Events.
Aber ist erstmal ein Gedankenentwurf...@GPC
Danke, das werd ich mal ändern
Was WinApi/gtk+ angeht steht da aber auch bei den Plattformen z.T. schon dabei.
-
Hi phlox,
Ich fände es klasse wenn du einen FAQ Beitrag oder einen Artikel über die Installation von wxWidgets auf Windows schreiben könntest, irgendwie hab ich das Gefühl das diese Frage noch sehr viel öfter aufkommen wird
Danke.
BR
Vinzenz
-
evilissimo schrieb:
Hi phlox,
Ich fände es klasse wenn du einen FAQ Beitrag oder einen Artikel über die Installation von wxWidgets auf Windows schreiben könntest, irgendwie hab ich das Gefühl das diese Frage noch sehr viel öfter aufkommen wird
Danke.
BR
VinzenzJo, werd ich mal in angriff nehmen, aber der Artikel sollte da auch weiterhelfen.
Und evtl. die Leute freundlich auf INSTALL-MSW.txt hinweisen, da steht das drin. (und noch vielmehr)
-
Naja, es gibt ja wxPack, welches fertige Developer-Binaries bereit stellt, weil es heute ganz einfach umständlich geworden ist, wxWidgets zu bauen.
Ich würde einfach auf wxPack verweisen und gut ist.
-
So, hab jetzt noch die Sourcen für das HelloWorld hochgeladen.
Hat jemand noch irgendwelche Fehler oder Verbesserungen?
Sonst kann der Artikel so raus...
-
Willst du nicht noch auf wxPack verweisen? (zwei drei Sätze am Artikelanfang reichen ja schon) Das ist besonders für Einsteiger und Leute die einfach loslegen wollen, sehr interessant. Denn es sind schon fertig gebaute wx-Libs, VC++-Wizards, GUI-Designer usw. dabei. Der Frustrastionsfaktor für wx-Einsteiger oder allgemein Einsteiger wird da erheblich gesenkt. Man muß sich nicht mit Dingen rumschlagen, die nicht nötig sind und es ist alles dabei um arbeiten zu können.
Hier die URL:
http://wxpack.sourceforge.net/
-
Hatte leider noch keine Zeit mir wxPack mal genauer anzusehen, recht
hast du natürlich schon, das es für Einsteiger bestimmt einfacher ist.Aber ich finds recht verwirrend, wenn man 165 MB runterladen muss, um
sich ne Lib zu installieren. Erwähnen werd ichs aber aufjedenfall.
Ist für Einsteiger sicher ne gute Sache, wenn man Visual Studio hat gibts
ja sogar nen Installer.So, wxPack ist drin.
-
alte version gelöscht... (neue am ende des Artikels)
-
Ist etwas spät aber: Kannst du den Codeblock in Kapitel 2 in der Breite reduzieren?
So dass er auch auf kleinere Bildschirme passt?Ich kriege den ja hier bei der 1680er Auflösung nicht drauf.
-
Ja klar. Hab die Codeblöcke noch mal überarbeitet...
-
Und wie sidewinder in deinem Profil schon gefragt hat: sind die zeilenumbrüche absicht? Der erklärende Text füllt meinen Bildschirm nicht mal bis zur hälfte.
-
ness schrieb:
Und wie sidewinder in deinem Profil schon gefragt hat: sind die zeilenumbrüche absicht? Der erklärende Text füllt meinen Bildschirm nicht mal bis zur hälfte.
Ich bins so gewöhnt, wenn die Editbox im Editor zu Ende ist, einen Zeilenumbruch zu machen. Bei längeren Texten verliere ich sonst im Editor die Übersicht.
Ich frag mich nur, warum das niemanden aufgefallen ist, während der Artikel hier recht lange auf R war...
-
lol, du bist mir einer. Die breitesten Codeblocks, aber nach allen paar Wörtern ein Zeilenumbruch im Fließtext
-
rüdiger schrieb:
lol, du bist mir einer. Die breitesten Codeblocks, aber nach allen paar Wörtern ein Zeilenumbruch im Fließtext
Ja es ist irgendwie gewohnheit geworden, evtl. könnte man ja mal die Textbox vergrössern in der posting.php (hm, seh gerade das es dafür sogar Buttons gibt :))
Und die Codeblöcke sind Copy & Paste.Überarbeite den Artikel aber gerade wegen der Textumbrüche.