wxWidgets mit C++ – Teil 4
In diesem Artikel werden einige Steuerelemente näher betrachtet, ein Dialog erstellt und ich zeige Code Snippets meines aktuellen Projekts. Mit einigen Tipps aus der Praxis solltest du nun auch in der Lage sein künftig Fenster und Dialoge unabhängig von der Plattform zu erstellen.
wxWidgets mit C++ – Teil 4
wxWidgets definiert seine Steuerelemente in einer Hierarchie. Das ist bei allen mir bekannten GUI Systemen so. Am Anfang steht ein Fenster, ein solches haben wir bereits im letzten Artikel über das RAD Tool definiert. Repräsentiert wird ein Fenster durch eine Klasse die von wxFrame erbt:
class Editor : public wxFrame
Im Konstruktor dieser Klasse wird der Inhalt des Fensters definiert. In meinem Fall ist das hauptsächlich das Menü, mein Fenster enthält aber beispielsweise auch einen Sizer, das sind unsichtbare Elemente die dazu dienen den Platz aufzuteilen (beispielsweise in Zeilen und Spalten). Ein Sizer wird im Konstruktor angelegt und dem übergeordneten Element übergeben:
wxBoxSizer* boxSizer1 = new wxBoxSizer(wxVERTICAL); boxSizer1->SetMinSize(0, 0); this->SetSizer(boxSizer1);
Man erkennt, dass der Sizer nicht viel macht. Er teilt den Platz vertikal, mehr Informationen wurden nicht gesetzt. Als nächstes definiere ich noch ein leeres Panel und weise diesem eine Farbe zu:
m_mainPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(634, 476)), wxTAB_TRAVERSAL); m_mainPanel->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT)); boxSizer1->Add(m_mainPanel, 1, wxEXPAND, WXC_FROM_DIP(5));
Baut man nun das Programm, dann erhält man ein leeres Fenster mit den Dimensionen, die im Panel definiert wurden. Es fehlt nun noch das Menü, das wird so erstellt:
m_menuBar = new wxMenuBar(0); this->SetMenuBar(m_menuBar); m_menuFile = new wxMenu(); m_menuBar->Append(m_menuFile, translator.translate("menuFile")); m_menuReinitialize = new wxMenuItem(m_menuFile, wxID_ANY, translator.translate("menuReinitialize"), wxT(""), wxITEM_NORMAL); m_menuFile->Append(m_menuReinitialize);
Eine neue Menüleiste (wxMenuBar) wird erstellt und direkt dem Fenster zugewiesen. Danach legt man Menüs an (wxMenu), das sind die sichtbaren Menünamen in der Menüleiste. Jedem Menü kann man nun beliebig viele Menü Elemente (wxMenuItem) hinzufügen, die im aufgeklappten Zustand angezeigt werden. Das fertig gebaute Programm zeigt nun ein Fenster mit den von uns definierten Menüs. Diese kann man öffnen und sich die einzelnen Menüitems ansehen. Funktion ist noch keine hinterlegt.
Events
Am Ende vom Konstruktor kann man nun für jeden Menüeintrag ein Event definieren. Das ist eine Funktion der Fensterklasse die bei einer bestimmten Aktion ausgeführt wird. Bei einem Menüeintrag macht die Aktion „Menu selected“ am meisten Sinn:
this->Connect(m_menuExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Editor::OnExit), NULL, this);
Mit dem wxCommandEventHandler wird die Funktion benannt die über den definierten Event aufgerufen werden soll. Um das Fenster zu schließen (der Menüpunkt beenden heißt bei mir menuExit) wird folgende Funktion definiert:
void Editor::OnExit(wxCommandEvent& event) { wxUnusedVar(event); Close(); }
Um sauber zu programmieren müssen wir den registrierten Eventhandler bei der Zerstörung der Klasse auch wieder aufheben. Im Destruktor benötigen wir also folgende Zeile für den zuvor erstellten OnExit Eventhandler:
this->Disconnect(m_menuExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Editor::OnExit), NULL, this);
Dialog öffnen
Ein Fenster schließen ist zwar ein Event, den man in jedem Programm benötigt, meist wollen wir aber etwas konstruktivere Aktionen ausführen. Eine solcher Aktionen ist das Öffnen eines neuen Dialogfensters. Auch das ist mit wxWidgets sehr einfach. Bei einem Klick auf den Menüeintrag „Vereine“ (menuTeams) wird in meinem Programm ein Dialog zur Selektion eines Teams eines bestimmten Landes geöffnet. Das Event sieht folgendermaßen aus:
void Editor::OnMenuTeams(wxCommandEvent& event) { DialogClubselect dlg(this); dlg.ShowModal(); }
Ich instanziere einfach ein neues Objekt vom Typ des Dialogs und übergebe diesem das Objekt vom aktuellen Fenster (nicht auf die Hierarchie vergessen!). Mit der Methode ShowModal() wird dieser Dialog modal angezeigt. Modal bedeutet, dass nur eingaben in diesem Dialog möglich sind und das Fenster im Hintergrund inaktiv wird. Moment langsam: woher kommt dieser Dialog nun her? Das ist recht einfach erklärt. So wie oben beschrieben das Fenster der Applikation als Klasse definiert wurde kann man auch einen Dialog definieren. Das funktioniert super einfach, man erstellt eine neue Klasse die von wxDialog erbt:
class DialogClubselect : public wxDialog
Auch dort kann man wieder im Konstruktor dessen Steuerelemente definieren, Events anlegen und andere Dialoge oder Fenster öffnen.
Übersetzungen
Bei genauer Betrachtung meiner Screenshots erkennst du vermutlich eine Mischung aus englischer und deutscher Sprache. Das liegt daran, dass ich das Programm immer auf Mehrsprachigkeit auslege und erst einen Teil übersetzt habe. wxWidgets eignet sich sehr gut dazu in einer Übersetzungsdatei (beispielsweise XML) für jedes Steuerelement einen Eintrag mit der Bezeichnung mehrerer Sprachen zu hinterlegen. Zur Laufzeit des Programms bestimmt dann eine Einstellung welche Sprache angezeigt werden soll. Für Sprachen die von links nach rechts schreiben ist damit die Übersetzung sehr einfach gelöst. Muss man beispielsweise auch Arabisch einbauen wird die Aufgabe etwas komplizierter…
Fazit
Mit einigen Beispielen aus der Praxis beende ich meine Artikelserie über wxWidgets mit C++. In den 4 Teilen habe ich hoffentlich genug Infos gegeben um rasch und effizient ein eigenes Plattform unabhängiges GUI für euer nächstes Projekt zu bauen. Ich hoffe ich konnte dich für die wxWidgets Bibliothek begeistern. Meiner Meinung nach sind Plattform unabhängige GUIs heute pflicht. Setzt man nur auf ein proprietäres System verwehrt man von vornherein Nutzern die Ausführung. Ich finde diesen Ansatz nicht zeitgemäß.
Was denkst du über Plattform unabhängige GUIs? Welche anderen kennst du und kannst du empfehlen?
Teil 1 | Teil 2 | Teil 3| Teil 4