Beispiel: Fensterinformationen aus einer Glade-Datei laden (gtkmm)
-
Moin allerseits,
da hier ja bereits fleissig Beispiele fuer gtkmm geschrieben werden, will ich
auch mal eins schreiben, da ich auch fuer mein Abschlussprojekt entsprechendes
angewendet habe und euch das nicht vorenthalten will.Wie der Titel bereits erahnen laesst, kann man Fensterinformationen in einer
sogenannten Glade-Datei speichern. Dies ist nichts weiter als eine XML-Datei,
welche von dem Designer-Tool Glade erzeugt wird.Mit Glade kann ich also Fenster Designen und diese Abspeichern.
Das schoene: Ich kann das Design jederzeit aendern, ohne die Anwendung neu
uebersetzen zu muessen. Es werden keinerlei Informationen ueber das
Fensterdesign im Quellcode codiert, sondern lediglich aus der Glade-Datei
geladen.Zunaechst einmal muss man natuerlich ein Fenster mittels des Designer-Tools
Glade erstellen und abspeichern.Ich erlaube mir einmal, die entsprechende Datei hier zu posten:
example.glade:
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> <!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> <glade-interface> <widget class="GtkWindow" id="MainWindow"> <property name="width_request">340</property> <property name="visible">True</property> <property name="title" translatable="yes">Hallo Welt!</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_CENTER</property> <property name="modal">False</property> <property name="resizable">False</property> <property name="destroy_with_parent">False</property> <property name="decorated">True</property> <property name="skip_taskbar_hint">False</property> <property name="skip_pager_hint">False</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DESKTOP</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> <child> <widget class="GtkVBox" id="vbox1"> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">0</property> <child> <widget class="GtkLabel" id="halloWeltLabel"> <property name="height_request">270</property> <property name="visible">True</property> <property name="label" translatable="yes">Hallo Welt!</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> </widget> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">False</property> </packing> </child> <child> <widget class="GtkHButtonBox" id="hbuttonbox1"> <property name="visible">True</property> <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property> <property name="spacing">0</property> <child> <widget class="GtkButton" id="cmdBeenden"> <property name="visible">True</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">_Beenden</property> <property name="use_underline">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> </widget> </child> </widget> <packing> <property name="padding">0</property> <property name="expand">True</property> <property name="fill">True</property> </packing> </child> </widget> </child> </widget> </glade-interface>
Ihr koennt diese Datne in einer Datei abspeichern und mit Glade laden. Es
handelt sich hierbei um ein Fenster (MainWindow), welches eine VBox mit zwei
Elementen enthaelt. Bei dem ersten Element handelt es sich um ein Label mit
der Aufschrift "Hallo Welt!" und bei dem zweiten Element handelt es sich um
eine HButtonBox, also eine horizontale Button Box, welche einen Button enthaelt
mit der Aufschrift "Beenden" enthaelt.Zunaechst einmal muessen wir auf das Fenster zugreifen koennen, wir definieren
uns daher eine Klasse, welche von Gtk::Window erbt und diejenigen Elemente
als Member enthaelt, mit denen wir interagieren wollen.Ich habe den Beispiel-Code bereits kommentiert, sodass ich mir eine extra
Erklaerung an dieser Stelle spare, sie waere auch nichts weiter als eine
Wiederholung der Kommentare.mainwindow.hpp:
#ifndef mainwindowHPP #define mainwindowHPP #include <gtkmm.h> #include <libglademm.h> class MainWindow : public Gtk::Window { private: //zugriff auf glade-datei Glib::RefPtr<Gnome::Glade::Xml> &refXml; //der button zum beenden der anwendung Gtk::Button* btnBeenden; public: /* wir wollen die fenster informationen aus einer glade-datei laden. mittels 'get_widget_derived' (s. main.cpp) kann auf eine abgeleitete klasse zugegriffen werden. zum instanziieren ruft 'get_widget_derived' einen CTor auf, welcher eben diese signatur haben muss. 'base' ist hierbei der c-typ (gtk+) und enthaelt bereits alle relervanten informationen ueber das fenster. 'refXml' ist hierbei wichtig, da wir damit die member der klasse aus der glade-datei herauslesen und den klassenmembern zuweisen koennen (siehe implementierung des ctor) */ MainWindow(GtkWindow* base, Glib::RefPtr<Gnome::Glade::Xml> &refXml); //beendet die Anwendung virtual void cmdBeenden() { hide(); } }; #endif
Natuerlich benoetigen wir auch noch die Implementierung des CTors.
mainwindow.cpp:
#include "mainwindow.hpp" using namespace Gtk; /* hier sieht man nun, warum wir 'refXml' benoetigen. ueber 'refXml' greifen wir nun auf die information fuer den beenden-button zu und lesen diese aus der glade-datei. wie einem fenster, wird auch fuer den button mittels 'get_widget' die information aus der glade-datei herausgelesen. */ MainWindow::MainWindow(GtkWindow* base, Glib::RefPtr<Gnome::Glade::Xml> &refXml) : Window(base), refXml(refXml) { //pointer auf die 'cmdBeenden'-instanz holen refXml->get_widget("cmdBeenden", btnBeenden); if(btnBeenden) //das clicked-signal mit der elementfunktion 'cmdBeenden' verbinden btnBeenden->signal_clicked().connect(mem_fun(*this, &MainWindow::cmdBeenden)); }
Letztlich benoetigen wir noch die main.cpp.
main.cpp:
#include <iostream> #include "mainwindow.hpp" using namespace std; using namespace Gtk; int main(int argc, char* argv[]) { Main mainApplication(argc, argv); try { /* gladedatei oeffnen, um fensterinformationen herauszulesen der zweite parameter gibt an, dass wir lediglich das fenster mit diesem namen instanziieren wollen. wuerden wir diesen parameter weglassen, so wuerden saemtliche, in der datei definierten, fenster instanziiert werden */ Glib::RefPtr<Gnome::Glade::Xml> refXml = Gnome::Glade::Xml::create("example.glade", "MainWindow"); MainWindow* mainWindow(0); /* um auf eine instanz zugreifen zu koennen, nutzt man die element- funktion 'get_widget'. Da wir jedoch eine von Gtk::Window abgeleitete Klasse nutzen, muessen wir 'get_widget_derived' aufrufen. */ refXml->get_widget_derived("MainWindow", mainWindow); //wenn es eine entsprechende instanz gibt... if(mainWindow) Main::run(*mainWindow); //...dann koennen wir das fenster nun anzeigen else { /* ...oder es konnte es aus irgendwelchen gruenden nicht nicht dem zeiger 'mainWindow' zugewiesen werden? */ cout<<"Hauptfenster konnte nicht geladen werden!"<<endl; return 1; } /* falls beim parsen der glade-datei ein problem gibt, dann wird eine exception geschmissen, die wir abfangen sollten */ } catch(Gnome::Glade::Xml::Error& xmlError) { cout<<xmlError.what()<<endl; cin.get(); return 1; } return 0; }
So, ich hoffe das Prinzip ist klar geworden. Man kann hiermit sehr schoen die
grafischen Elemente vom Code trennen und hat nicht die ganzen
Design-Informationen im Code stehen, was diesen natuerlich auch unheimlich
aufblaeht.Bleibt noch zu erwaehnen, dass ihr zu eurer Anwendung noch zusaetzlich die
Library 'glademm-2.4' hinzulinken muesst.So, Fehler einfach korregieren :). Ich hoffe mal das meine Erklaerungen im Code
ok sind, mit der Ausdrucksweise tu ich mir immer schwer ;).mfg
v R