Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 15 GTK+
  gp 15.1 Was ist GTK+?
    gp 15.1.1 Was sind GDK und Glib?
    gp 15.1.2 Schnittstellen von GTK+ zu anderen Programmiersprachen
    gp 15.1.3 GTK+ und GNOME
    gp 15.1.4 GTK+ Version 1.2 und 2.x
    gp 15.1.5 GTK+-Aufbau des Kapitels
  gp 15.2 GTK+-Anwendungen übersetzen
  gp 15.3 Eine Einführung in die Glib-Bibliothek
    gp 15.3.1 Datentypen
    gp 15.3.2 Routinen
    gp 15.3.3 Assertions-Funktionen
    gp 15.3.4 Speicherverwaltung
    gp 15.3.5 Stringbearbeitung
    gp 15.3.6 Selbstverwaltender Stringpuffer
    gp 15.3.7 Timer
    gp 15.3.8 Dynamische Arrays
    gp 15.3.9 Listen, Hashtabellen und binäre Bäume
    gp 15.3.10 Ausblick Glib
  gp 15.4 Grundlagen der GTK+-Programmierung
    gp 15.4.1 Die Umgebung initialisieren
    gp 15.4.2 Widgets erzeugen und ggf. die Attribute setzen
    gp 15.4.3 Eine Callback-Funktion einrichten, um Events abzufangen
    gp 15.4.4 Eine GTK+-Anwendung beenden
    gp 15.4.5 Die hierarchische Anordnung der Widgets definieren
    gp 15.4.6 Widgets anzeigen
    gp 15.4.7 Signale und Events abfangen und bearbeiten – (Events-)Verarbeitungsschleife
    gp 15.4.8 GTK+ und Umlaute (Zeichenkodierung)
  gp 15.5 Fenster – GtkWindow
    gp 15.5.1 Dialogfenster (Dialogboxen)
    gp 15.5.2 GtkMessageDialog
  gp 15.6 Anzeige-Elemente
    gp 15.6.1 Text – GtkLabel
    gp 15.6.2 Trennlinie – GtkSeparator
    gp 15.6.3 Grafiken – GtkImage
    gp 15.6.4 Statusleiste – GtkStatusbar
    gp 15.6.5 Fortschrittsbalken – GtkProgressBar
  gp 15.7 Behälter
    gp 15.7.1 Boxen – GtkBox
    gp 15.7.2 Aufteilungen, Register und Button-Box
    gp 15.7.3 Tabellen – GtkTable
    gp 15.7.4 Ausrichtung – GtkAlignment
  gp 15.8 Buttons und Toogled-Buttons
    gp 15.8.1 Buttons allgemein
    gp 15.8.2 Radio-Buttons (GtkRadioButton)
    gp 15.8.3 GtkRadioButton, GtkCheckButton und GtkToggleButton
    gp 15.8.4 Signale für Buttons (GtkButton)
  gp 15.9 Dateneingabe
    gp 15.9.1 Textfelder – GtkEntry
    gp 15.9.2 Schieberegler – GtkScale
    gp 15.9.3 Zahlenfelder – GtkSpinButton
    gp 15.9.4 Einstellungen – GtkAdjustment
    gp 15.9.5 GtkEditable
  gp 15.10 Menü und Toolbar
    gp 15.10.1 Menü – GtkItemFactory
    gp 15.10.2 Toolbar – GtkToolbar
    gp 15.10.3 Options-Menü – GtkOptionsMenu
    gp 15.10.4 Combo-Boxen – GtkCombo
  gp 15.11 Mehrzeiliger Text
    gp 15.11.1 Text(editor) – GtkTextView, GtkTextBuffer
    gp 15.11.2 Scrollendes Fenster – GtkScrolledWindow
  gp 15.12 Auswählen (Selection)
    gp 15.12.1 Dateiauswahl – GtkFileSelection
  gp 15.13 Events
  gp 15.14 Weitere Widget- und GTK+-Elemente im Überblick


Rheinwerk Computing

15.4 Grundlagen der GTK+-Programmierung  downtop

Anwendungen mit einer grafischen Oberfläche (GUI) können sehr komplex werden. Daher werden Sie erst die grundlegenden Schritte kennen lernen, die nötig sind, um eigene GTK+-Anwendungen zu schreiben. Wenn Sie die grundlegenden Eigenschaften kennen und schätzen gelernt haben, wird es Ihnen nicht mehr sonderlich schwer fallen, komplexere GTK+-Programme zu schreiben, denn im Endeffekt wird immer nach demselben Schema verfahren. Folgende Schritte sind (fast) immer nötig, um eine GTK+-Anwendung zu erstellen:

gp  die Umgebung initialisieren
gp  Widgets erzeugen und ggf. die Attribute setzen
gp  eine Callback-Funktion einrichten, um Events abzufangen
gp  die hierarchische Anordnung der Widgets definieren
gp  Widgets anzeigen
gp  Signale und Events abfangen und bearbeiten – (Events-)Verarbeitungsschleife

Auf den folgenden Seiten soll nun auf die einzelnen Schritte etwas genauer eingegangen werden, ohne jetzt schon die einzelnen Widgets im Detail zu beschreiben.


Rheinwerk Computing

15.4.1 Die Umgebung initialisieren  downtop

Der erste Schritt einer jeden GTK+-Anwendung ist es, die Umgebungsvariablen zu initialisieren. Dabei werden die Standardwerte für z. B. Farben vergeben. Die Funktion, mit der Sie dies realisieren, lautet:

#include <gtk/gtk.h>
void gtk_init(int *argc_ptr, char ***argv_ptr);

Bei argc_ptr handelt es sich um eine Adresse des ersten Parameters der Standard-C-Funktion main(), welche die Anzahl der Argumente aus der Kommandozeile beinhaltet. Der zweite Parameter argv_ptr ist dann eine Adresse auf den zweiten Parameter der main()-Funktion, und der beinhaltet die Werte der einzelnen Argumente aus der Kommandozeile. Mit gtk_init() wird die Verbindung zum X-Server aufgebaut, daher können Sie in der Kommandozeile mit der Option -display display_name die Anwendung auf einem anderen Display ausführen. Für die Syntax des Namens des Displays lesen Sie bitte die Dokumentation, da diese Angabe je nach System variieren kann. Des Weiteren wird mit der Funktion gtk_init() automatisch mit atexit() eine Clean-up-Funktion eingerichtet.


Hinweis   Es können auch zwei X-Server lokal laufen, es muss nicht ein anderer Rechner sein.



Rheinwerk Computing

15.4.2 Widgets erzeugen und ggf. die Attribute setzen  downtop

Widgets können mit den gtk_xxx_new()-Funktionen erzeugt werden – wobei xxx für den Typ des Widgets steht, das erzeugt werden soll. Es gibt eine enorme Anzahl von Widgets, die verständlicherweise nicht alle im Buch erwähnt werden können. Die Funktionen gtk_xxx_new() sind als gleichwertig zu einem Konstruktor in C++ oder Java anzusehen. Mit den Funktionen wird Speicher für ein neues Objekt alloziiert.

Noch umfangreicher ist die Anzahl der Routinen, mit denen Sie die Attribute der Widgets verändern können. Für einzelne Widgets gibt es häufig mehrere Funktionen. Die Funktionen, mit denen Sie die Attribute von Widgets verändern können, haben alle die Syntax gtk_xxx_set_yyy(). xxx steht dabei für das Widget und yyy für das Attribut, das verändert werden soll. Wenn Sie z. B. den Titel des Fensters setzen wollen, so geschieht dies mit dem Aufruf gtk_window_set_title( ... ).

Alle Widgets sind Unterklassen der GtkWidget-Basisklasse, weshalb Sie auch den Typ GtkWidget verwenden können, um ein Widget zu referenzieren; wobei im Beispiel des Buchs meistens immer der Typ des Widgets angegeben wird. Anstatt ein Fenster wie folgt zu referenzieren:

GtkWidget  *win;

wird im Buch immer folgende Schreibkonvention verwendet:

GtkWindow  *win;

Daran erkennt man gleich, worum es sich bei dem Widget handelt, und somit lässt sich auch schneller die entsprechende Referenzseite des Widgets finden. Was Sie später in der Praxis verwenden, bleibt natürlich Ihnen überlassen. (Verfallen Sie aber nicht der ungarischen Notation, wie z. B. Microsoft sie gerne verwendet, d. h. GtkWindow *wMain, *wPanel etc., sie ist viel zu fehleranfällig.) Wenn Sie zum Erzeugen von neuen Widgets den Konstruktor GtkWidget verwenden, benötigen einige Funktionen einen genaueren Typ als GtkWidget. In solch einem Fall gibt es spezielle Makros, die den Typen casten.

Die zweite Möglichkeit, ein Widget zu erzeugen, die auch in diesem Buch hier vorwiegend verwendet wird, besteht in der Funktion g_object_new().

GtkObject* g_object_new (
           GtkType type, const gchar *first_arg_name, ... );

Hiermit erzeugen Sie ein Objekt (Widget) type mit den Eigenschaften, die Sie mit den weiteren Parametern (first_arg_name) angeben können. Abgeschlossen wird diese variabel lange Argumentenliste mit NULL. Zurückgegeben wird ein Zeiger auf das neue Objekt (Widget). Das Prinzip ist einfach und typisch objektorientiert. Sie wollen z. B. ein einfaches Fenster erzeugen:

GtkWindow *win;
...
win = g_object_new( GTK_TYPE_WINDOW, NULL );

Anstatt also den Funktionsaufruf wie gtk_xxx_new() zu verwenden, führen Sie hierbei g_object_new(GTK_TYPE_XXX, NULL) aus. Aber im Gegensatz zu gtk_xxx_new() können Sie beim Erzeugen eines neuen Objektes gleich weitere Eigenschaften des Objektes mit angeben. Um beim Beispiel des Fensters zu bleiben:

   /* Fenster mit Eigenschaften anlegen */
   win = g_object_new( GTK_TYPE_WINDOW,
                       "title", "Ein leeres Fenster",
                       "default-width",  300,
                       "default-height", 200,
                       "resizable", TRUE,
                       "window-position", GTK_WIN_POS_CENTER,
                       "border-width", 5,
                       "icon", pic,
                       NULL );

Mit den Funktionen gtk_xxx_set_yyy() müssten diese Angaben häufig mühevoll mit mehreren Funktionen übergeben werden. An den konstanten Namen des ersten Parameters zu kommen, sollte im Prinzip keine Probleme bereiten. Wollen Sie z. B. ein Objekt vom Typ GtkSpinButton erzeugen, lässt sich dies ganz einfach auf den ersten Parameter projizieren.

GtkSpinButton => GTK_TYPE_SPIN_BUTTON

Gtk wird zu Beginn des Widgets entfernt, und vor jeden Großbuchstaben des Widgets wird ein Unterstrichzeichen hingesetzt. Natürlich wird, wie bei Konstanten üblich, der Typ großgeschrieben (dies ist keine Regel, sondern nur ein Tipp). Aber Sie werden dies besser verstehen, wenn Sie die Beispiele in der Praxis einsetzen werden.


Rheinwerk Computing

15.4.3 Eine Callback-Funktion einrichten, um Events abzufangen  downtop

Was Events sind und wie Sie darauf regieren können, haben Sie bereits im Kapitel zur X-Programmierung erfahren. Jetzt wollen Sie sicherlich wissen, wie eine solche Ereignisverarbeitung in GTK+ realisiert wird. In GTK+ wird hierbei zwischen Ereignissen (Events) und Signalen unterschieden; wobei diese Signale hier nicht mit den Linux-typischen Signalen zu vergleichen sind! Tritt z. B. ein Ereignis ein (wie ein Mausklick auf einen Button), wird programmintern ein Signal gesendet (in diesem Fall spricht man vom emittiert). Gewöhnlich führt allerdings jedes Ereignis zur Auslösung eines oder mehrerer Signale. Ereignissignale sind zum Beispiel an der Endung -event zu erkennen. Hier ist wieder derjenige von Vorteil (also Sie mit diesem Buch), der bereits Vorkenntnisse mit der X-Programmierung hat. Allerdings müssen Sie sich jetzt nicht mehr um die Implementierung kümmern, sondern vielmehr darum, wie Sie mit den Ereignissignalen arbeiten müssen. Auf die Events und deren Behandlung wird noch extra in einem Abschnitt eingegangen.


Hinweis   Da mittlerweile die Version 2.x von GTK+ vorliegt, aber auf vielen Rechnern höchstwahrscheinlich zusätzlich noch die Version 1.2 von GTK+ installiert ist, gibt es hier einige Veränderungen. In der Version 1.2 wird zum Einrichten einer Callback-Funktion gtk_signal_connect() verwendet. In der Version 2.0. wurde diese Funktion in die Glib ausgelagert und hat somit jetzt kein gtk_ mehr voranstehen, sondern ein g_, also g_signal_connect().


Der Aufbau von Signalen entspricht einem typischen Klassenbaum (siehe Abb. 14.2), z. B. bei den Buttons. Ganz oben in der Klasse steht das Widget GtkObject mit dem Signal destroy – was die Beendigung bedeutet. Anschließend folgt im Hierarchiebaum GtkWidget, das weiterhin unabhängig vom eigentlichen Widget bestimmte Signale empfangen und verarbeiten kann. So ist die Größe, ob sichtbar oder versteckt, ein Signal, das alle GtkWidget besitzen und zurückgegeben werden kann. Ein Klasse tiefer finden Sie GtkContainer, das wiederum speziell für den Container eingehende Signale verarbeiten kann. Tiefer steigend befindet sich dann das Widget GtkBin, das keinerlei Signale empfangen kann. Jetzt erst kommen Sie im Klassenbaum zum Widget GtkButton. Dem Button können Sie die Signale clicked, enter, leave, pressed oder released erteilen – sprich, diese Signale können Sie für einen Button mittels g_signal_connect() einrichten (registrieren).


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 15.2    Der Klassenbaum von GtkButton mit den Signalen


Wenn Sie eine Callback-Funktion geschrieben haben, müssen Sie diese registrieren, um sie aufzurufen, wenn ein bestimmtes Signal emittiert wird. Registriert wird eine Callback-Funktion mit der Funktion:

gulong g_signal_connect( gpointer      *object,
                         const gchar   *name,
                         GCallback     func, 
                         gpointer      func_data );

Die Bedeutungen der einzelnen Parameter sind folgende:

gp  object – Das Objekt, womit Sie die Callback-Funktion verbinden wollen. Hier wird häufig ein Casting (GTK_OBJECT( widget )) verwendet.
gp  name – Das Signal, womit die Callback-Funktion aufgerufen werden soll, wie clicked, wenn ein Button mit der Maustaste geclicked wurde.
gp  func – Die Callback-Funktion, die Sie registrieren wollen. Bei der g_-Version (GTK+ 2.x) müssen Sie diese Funktion mit G_CALLBACK(func) casten – bei der gtk_-Version (GTK+ 1.2) war dies GTK_SIGNAL_FUNC(func).
gp  func_data – Hier können Sie der Callback-Funktion noch zusätzliche Daten übergeben, wenn diese aufgerufen wird. Wollen Sie der Callback-Funktion keine Daten übergeben, können Sie hier auch NULL angeben.

Mit g_signal_connect() haben Sie eine Callback-Funktion eingerichtet. Die Syntax einer solchen Callback-Funktion, die Sie gewöhnlich selbst schreiben müssen, sieht folgendermaßen aus:

type function( parameter_liste );

So sieht beim Anklicken eines Buttons Ihre Callback-Funktion aus:

static void my_buttonCB( GtkButton *clicked, gpointer data ) {
   /* Ausgabe für die Konsole */
   g_print("Callback my_buttonCB aufgerufen (%s)\n",
            (gchar *)data );
}

clicked ist hierbei der Button, der angeklickt wurde, und data sind die Daten, die beim Einrichten des Signalhandlers mittels g_signal_connect() mit übergeben werden (falls nicht NULL). Diese Funktion registrieren Sie in der Praxis so:

g_signal_connect(GTK_OBJECT ( button ),  /* für welches Widget */
                 "clicked",              /* welches Signal     */
                 G_CALLBACK(my_buttonCB),/* welche Funktion    */
                 "Daten");               /* Daten für Funktion */

Rheinwerk Computing

15.4.4 Eine GTK+-Anwendung beenden  downtop

Zwar wird das Thema der Events noch in einem anderen Kapitel ausführlicher behandelt, doch Folgendes gehört zur Grundausstattung einer GTK+-Anwendung: Gemeint ist die Beendigung einer Anwendung. Wenn Sie Ihre GTK+-Anwendung starten und vom Rahmen des Window-Managers aus beenden wollen, wird sich das Fenster Ihrer Anwendung zwar schließen lassen, wohl aber nicht beenden, wenn Sie nicht spezielle Vorkehrungen treffen. Einfach gesagt, die Anwendung läuft still und ruhig im Hintergrund als aktiver Prozess weiter.

Intern passiert dabei Folgendes: Sie schließen das GTK+-Fenster mit dem Window-Manager, und es wird ein delete-event-Signal emittiert. Dieses Signal zeigt an, dass der Anwender das Programm beenden will. Jetzt müssen Sie als Programmierer entscheiden, ob das so in Ordnung geht. Wenn Sie das Beenden erlauben, wird das Signal destroy gesendet, und die Anwendung wird komplett beendet. Somit benötigen Sie zuerst eine Callback-Routine, die das Signal delete-event bearbeiten kann. Der Prototyp dieser Funktion sieht wie folgt aus:

static gboolean my_delete_Event( GtkWidget *widget,
                                 GdkEvent *event,
                                 gpointer data )

Der Parameter widget wird benötigt und beinhaltet u. a. die Kennungs-ID des Widgets, welches das Signal delete-event erzeugt hat. Der event-Parameter ist die Adresse einer Struktur, worin sich alles befindet, was Sie für das Event benötigen (darauf wird noch genauer eingegangen). Mit data können Sie beim Registrieren des Signalhandlers Daten an die Funktion mit übergeben. Wichtig ist der Rückgabewert der Funktion my_delete_Event(). Wenn dieser TRUE ist, wird verhindert, dass die Anwendung beendet wird. FALSE hingegen beendet die Anwendung, schließt also das Fenster und emittiert das Signal destroy. Somit sieht eine komplette Callback-Funktion zum Beenden der Anwendung über den Window-Manager folgendermaßen aus:

static gboolean my_delete_Event( GtkWidget *widget,
                                 GdkEvent *event,
                                 gpointer data ) {
  /* Ausgabe für die Konsole */
  g_print("Der Window-Manager will die Anwendung beenden\n");
       /* Unsern Segen zur Beendigung soll er haben */
 return FALSE;
}

Jetzt muss diese Funktion nur noch mit dem Fenster der Anwendung verbunden werden, da das Fenster die einzige Anwendung ist, die mit dem Window-Manager kommuniziert. Hierzu müssen Sie nur die g_signal_connect()-Funktion wie folgt verwenden:

g_signal_connect( GTK_OBJECT (fenster), "delete-event",
                  G_CALLBACK(my_delete_Event), NULL);

Jetzt hat unser Fenster das destroy-Event erhalten. Natürlich müssen Sie auch hierzu noch eine Callback-Funktion einrichten:

  g_signal_connect ( win, "destroy",
                     G_CALLBACK (end), NULL);

Die Callback-Funktion end sorgt nun mit dem Aufruf der Funktion gtk_main_quit() (dazu in Kürze mehr) für das absolute Ende der GTK+-Anwendung:

static void end (GtkWidget * widget, gpointer daten) {
  g_print ("Und tschuess!\n");
  /* Die Verarbeitungsschleife beenden */
  gtk_main_quit ();
}

Sicherlich mag Ihnen dieser Weg auf dem ersten Blick ein wenig umständlich vorkommen – und ja, Sie können die GTK+-Anwendung auch schneller beenden (ohne den aufwändigeren Weg). Allerdings sollten Sie dann bedenken, falls sich in der Anwendung noch nicht gespeicherte Daten befinden (wie bei einem Texteditor), dass diese bei der Beendigung auch weg sind, wenn Sie keine Vorkehrungen getroffen haben. Mit dem eben gezeigten Weg können Sie z. B. in der Callback-Funktion my_delete_Event() noch überprüfen, ob irgendwelche zusätzlichen Arbeiten vor Beendigung der Anwendung zu erledigen sind, und ggf. TRUE (anstatt FALSE) zurückgeben, womit die Anwendung nicht beendet wird (weil dadurch das Signal destroy nicht emittiert wird). Ein Beispiel dazu finden Sie etwas später mit dem Listing gtk1b.c.


Rheinwerk Computing

15.4.5 Die hierarchische Anordnung der Widgets definieren  downtop

Wenn Sie z. B. ein Fenster- und ein Button-Widget erzeugen, haben Sie noch lange nicht die Eltern-Kind-Beziehung zwischen den Widgets zustande gebracht. Vereinfacht heißt das, Sie müssen die Hierarchie errichten, damit GTK+ weiß, wie und wo die Widgets auf dem Bildschirm angezeigt werden sollen.

Um eine Eltern-Kind-Beziehung einzurichten, müssen Sie erst ein Kind-Widget zum verwaltenden Eltern-Widget hinzufügen. Der Funktionsaufruf hängt vom Eltern-Widget ab. Im Beispiel wird davon ausgegangen, dass das Fenster (GtkWindow) das Eltern-Widget ist – was gleichzeitig auch ein Abkömmling des GtkContainer-Widgets ist. Daher können Sie folgende Funktion verwenden:

void gtk_container_add( GtkContainer *container,
                         GtkWidget *widget );

Mit container geben Sie das Eltern-Widget an und mit widget das, das Sie zum container hinzufügen wollen.


Hinweis   Container sind Widgets, die wiederum andere Widgets enthalten können, und sind meistens für das Layout der Anwendung verantwortlich. Häufig werden Fenster als Container (zu Deutsch: Behälter) verwendet, worin sich alle anderen Widgets des Programms befinden.


Vorwiegend werden Box- und Tabellen-Widgets als Behälter für andere Widgets verwendet. Mit den Box- bzw. Tabellen-Widgets ist es recht einfach, die Widgets in einer bestimmten Lage zueinander anzuordnen. Natürlich lassen sich auch solche Behälter ineinander verschachteln, um die Form und Gestalt der Anwendung zu bestimmen. Wenn man ein Widget in einen Behälter steckt, spricht man von Packen. Die Widgets in einem Behälter werden als Kind-Widgets bezeichnet, wobei kein Kind-Widget gleichzeitig in verschiedenen Behältern vorkommen kann.

In den (bald) folgenden Listings werden Sie z. B. eine vertikale Box als Kind-Widget in den Behälter stecken – in einem Fall ist der Behälter z. B. ein Fenster. Womit Sie praktisch einen Behälter in einen Behälter packen – die Box ist zwar ein Widget, aber gleichzeitig ist sie auch ein Behälter. Die einfachste Möglichkeit, jetzt weitere Widgets in die Box zu packen, wäre mit der Funktion:

void gtk_box_pack_defaults( GtkBox *box, GtkWidget *widget );

Damit können Sie z. B. nacheinander weitere Widgets mit einer Standardeinstellung packen. Wurde eine Box z. B. mit der Funktion gtk_vbox_new() erzeugt, bedeutet dies, dass die weiteren Widgets mit der Funktion gtk_pack_defaults() vertikal angeordnet hinzugefügt werden.


Rheinwerk Computing

15.4.6 Widgets anzeigen  downtop

Jetzt haben Sie zwar Widgets erzeugt, die Anordnung und Hierarchie festgelegt, aber noch existieren diese Daten im Verborgenen (im Hauptspeicher). Sie haben jetzt zwei Möglichkeiten, die Widgets anzeigen zu lassen.

void gtk_widget_show( GtkWidget *widget );
void gtk_widget_show_all( GtkWidget *eltern_widget );

Mit der Funktion gtk_widget_show() können Sie die einzelnen Widgets nacheinander auf dem Bildschirm zeichnen lassen. Allerdings ist es doch sehr umständlich, wenn man bedenkt, dass umfangreichere Anwendungen schon mal ein paar Dutzend Widgets besitzen – schnell wird dabei ein Widget vergessen. Einfacher können Sie es sich mit der Funktion gtk_widget_show_all() machen. Hierfür müssen Sie nur das Eltern-Widget angeben, und alle sich darunter befindlichen Kinder-Widgets werden mit angezeigt (Ähnliches hatten Sie ja schon im Kapitel zum Xt-Toolkit gehabt).

Natürlich können Sie auch einzelne oder alle Widgets verstecken. Dies wird mit den entsprechenden Gegenstücken zu den eben erwähnten Funktionen gemacht:

void gtk_widget_hide( GtkWidget *widget );
void gtk_widget_hide_all( GtkWidget *eltern_widget );

Wird ein Widget nicht mehr benötigt, so sollte dieses mit der Funktion gtk_widget_destroy() freigegeben werden.

void gtk_widget_destroy ( GtkWidget *widget );

Rheinwerk Computing

15.4.7 Signale und Events abfangen und bearbeiten – (Events-)Verarbeitungsschleifdowntop

Wie schon bei der Xt-Bibliothek befindet sich die Verarbeitungsschleife am Ende des Codes. Die Syntax der Verarbeitungsschleife ist einfach:

void gtk_main();

Bis zur Funktion gtk_main() läuft das Programm erst iterativ ab. Nun wartet das Programm in der gtk_main()-Funktion auf ein Ereignis. Das Programm befindet sich praktisch in einer Endlosschleife. Tritt ein Ereignis auf, arbeitet GTK das Ereignis ab (vorausgesetzt, es wurde eine entsprechende Funktion für das Ereignis registriert) und springt anschließend wieder zur gtk_main()-Funktion zurück – außer bei diesem Ereignis handelt es sich um einen Aufruf der Funktion gtk_main_quit(), womit die Verarbeitungsschleife beendet und die Ausführung des Programms hinter gtk_main() fortgeführt wird.

void gtk_main_quit();

Wird gtk_main_quit() in einer Callback-Funktion aufgerufen, wird das Programm nicht unmittelbar beendet, sondern kehrt vorher noch hinter die Ausführung von gtk_main() zurück. Befindet sich hinter der gtk_main()-Funktion noch Code, wird dieser natürlich ausgeführt. Wollen Sie eine Anwendung unwiderruflich, egal von welcher Stelle aus beenden, können Sie dies mit der Funktion gtk_exit(), die gleichwertig zur Standard-C-Funktion exit() ist.

Hier der grafische Vorgang der Verarbeitungsschleife (gtk_main()) und gleichzeitig auch das Signalhandler-Modell von GTK+.


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 15.3    Signalmodell von GTK+



Rheinwerk Computing

15.4.8 GTK+ und Umlaute (Zeichenkodierung)  toptop

Sofern Sie Umlaute bzw. Nicht-ASCII-Zeichen in einer GTK+-Anwendung verwenden bzw. darstellen wollen, ohne eine Fehler- bzw. Warnmeldung zurückzubekommen wie z. B. [Invalid UTF-8], muss die Quelldatei in UTF-8 kodiert bzw. abgespeichert werden. Sofern Sie z. B. den GNU Emacs verwenden, sind Sie fein raus, denn dann reicht es aus, am Anfang des Listings folgende Steuerzeile einzufügen:

/* -*-coding: utf-8;-*- */

Bei anderen Editoren müssen Sie selbst nachsehen, ob eine solche Funktionalität vorhanden ist. Eventuell kann es sinnvoll sein, den Text mit dem Konverter iconv selbst vom latin1-Format zum utf-8-Format zu konvertieren. Ein Beispiel dazu könnte wie folgt aussehen:

$ iconv -f latin1 -t utf-8 gtk1.c > gtk1_utf8.c           

Hiermit konvertieren Sie aus der Quelldatei gtk1.c, die sich im latin1-Format befindet, eine UTF-8-codierte Datei namens gtk1_utf8.c, die jetzt in der Lage ist, auch Umlaute und Nicht-ASCII-Zeichen anzuzeigen.


Hinweis   Eine weitere Möglichkeit zur Lokalisierung von Software stellt GNU Gettext da. Mehr hierzu können Sie der Manual Page von gettext entnehmen.


UTF-8

Die UTF-8-Kodierung ist eine der wichtigsten, so dass es sich lohnen kann, sich näher damit zu befassen. UTF-8 ist kompatibel zur ASCII-Kodierung. Wie Sie wissen, werden ASCII-Zeichen mit einem Byte dargestellt. Somit ist jeder reine ASCII-Text auch ein reiner UTF-8-Text. Leider besteht hier auch das Problem, dass ein UTF-8-Text keine Reihe von gleich breiten Zeichen hat und somit iterativ zeichenweise zerlegt werden muss. Bei Verwendung von Nicht-ASCII-Zeichen, wie in unserem Land mit den Umlauten, führt diese Zerlegung zu unschönen Effekten. Um dieses Problem zu umgehen, finden Sie in der Glib hierzu einige nützliche Funktionen, die alle mit dem Präfix g_utf8_ beginnen.

Damit Sie sich nicht schon während der ersten Schritte mit GTK+ mit den verschiedenen Zeichenkodierungen herumschlagen müssen, wurde weitgehend auf Verwendung von Umlauten und Nicht-ASCII-Zeichen in den Beispielen verzichtet.

 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern