15.5 Fenster – GtkWindow
Der erste Schritt einer GTK+-Anwendung dürfte wohl meistens das Erzeugen eines Fensters sein. Das folgende Beispiel zeigt Ihnen, wie Sie ein solches (Behälter-)Widget der Klasse GtkWindow mit der Typenkennung GTK_TYPE_WINDOW erstellen und anzeigen können.
/* gkt1.c */
/* Ein leeres Fenster und Pixbuf */
#include <gtk/gtk.h>
static gint
delete_Event(GtkWidget * widget, GdkEvent event, gpointer daten){
g_print ("Das Fenster wird zerstoert!\n");
/* Nur mit FALSE wird die Anwendung wirklich beendet */
return FALSE;
}
static void end (GtkWidget * widget, gpointer daten) {
g_print ("Und tschuess!\n");
/* Die Verarbeitungsschleife beenden */
gtk_main_quit ();
}
int main (int argc, char **argv) {
GtkWindow *win;
GdkPixbuf *pic;
/* 1. Die Umgebung initialisieren */
gtk_init (&argc, &argv);
/* 2. Die Widgets erzeugen */
/* Eine Grafik in einen Pixbuf laden */
pic = gdk_pixbuf_new_from_file ("icon/at-work.gif", NULL);
/* 2a. Fenster mit den folgenden 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);
/* 3. Signalhandler (Callback-Funktion) einrichten */
g_signal_connect ( win, "delete-event",
G_CALLBACK (delete_Event), NULL);
g_signal_connect ( win, "destroy",
G_CALLBACK (end), NULL);
/* 4. Hier gibt es noch nichts zum Packen */
/* 5. (Widgets-)Fenster anzeigen */
gtk_widget_show_all (GTK_WIDGET (win));
/* 6. Hauptschleife von gtk-Verarbeitungsschleife */
gtk_main ();
g_print ("Die GTK-Hauptschleife wurde beendet\n");
return 0;
}
Das Programm bei der Ausführung:
$ gcc -Wall -o gtk1 gtk1.c \
`pkg-config gtk+-2.0 --cflags --libs`
$ ./gtk1
Im Großen und Ganzen muss eigentlich nicht mehr viel zu diesem Listing gesagt werden. Mit g_object_new() erzeugen Sie ein neues Fenster (GtkWindow) vom Typ GTK_TYPE_WINDOW mit einer variabel langen Liste von Eigenschafts-/Wertpaaren. Diese Liste wird mit NULL abgeschlossen:
"Eigenschaft1", Wert,
"Eigenschaft2", "Wert",
...,
NULL
Jede Eigenschaft ist abhängig von einem entsprechenden Datentyp, der als Wert gesetzt werden kann. Beispielsweise ist die Eigenschaft resizable vom Typ gboolean, und somit kann der Wert nur ein boolescher (TRUE oder FALSE) sein. title hingegen ist vom Typ gchararray, weshalb hier auch eine Zeichenkette für den Fenstertitel verwendet werden muss.
Folgende nützliche Eigenschaften können Sie für ein Fenster der Klasse GtkWindow verwenden (setzen) oder aber auch abfragen (ohne Garantie auf Vollständigkeit):
Tabelle 15.5
Eigenschaften für GtkWindow (GTK_TYPE_WINDOW)
Eigenschaft
|
Datentyp
|
Bedeutung
|
"allow-grow"
|
gboolean
|
Fenster darf vergrößert werden.
|
"allow-shrink"
|
gboolean
|
Fenster darf verkleinert werden.
|
"default-height"
|
gint
|
Höhe des neuen Fensters in Pixel
|
"default-width"
|
gint
|
Breite des neuen Fensters in Pixel
|
"destroy-with-parent"
|
gboolean
|
Wenn das Eltern-Widget zerstört wird, wird auch das Fenster zerstört.
|
"has-toplevel-focus"
|
gboolean
|
Ist das Fenster ganz vorne sichtbar und hat den Fokus, kann nur gelesen werden.
|
"icon"
|
GdkPixbuf
|
Ein Icon, welches das Fenster erhält. Im Beispiel anhand von GdkPixbuf demonstriert.
|
"is-active"
|
gboolean
|
Ist das Fenster aktiv, kann nur gelesen werden.
|
"modal"
|
gboolean
|
Wenn dieses Fenster existiert, können hier mit TRUE alle anderen Fenster in den Hintergrund gestellt werden (sprich, die Reaktion verweigern) – und zwar so lange, bis Sie die Angabe mit FALSE wieder rückgängig machen.
|
"resizable"
|
gboolean
|
Der Anwender darf die Größe des Fensters verändern.
|
"title"
|
gchararray
|
Ein String mit dem Titel des Fensters
|
"window-position"
|
GtkWindowPosition
|
Hier können Aufzählungswerte verwendet werden, womit die Position des Fensters auf dem Bildschirm bestimmt werden kann. Mögliche Angaben hierfür sind:
GTK_WIN_POS_NONE
Das Platzieren überlassen Sie dem Fenstermanager (Standard).
GTK_WIN_POS_CENTER
Zentriert in der Bildschirmmitte
GTK_WIN_POS_CENTER_ON_PARENT
Zentriert in der Mitte des Eltern-Widgets
GTK_WIN_POS_MOUSE
Wenn möglich, an der Position des Mauszeigers
|
Hinweis Damit in dieser Tabelle nicht alles hereingequetscht wirkt, wurden einige Eigenschaften in zwei Zeilen geschrieben – was Sie im Listing als kompletten String verwenden sollten!
Hinweis Die Reihenfolge, in der Sie die Eigenschafts-/Wertpaare angeben, ist frei wählbar. Es ist somit egal, ob Sie title vor die Eigenschaft icon setzen oder dahinter.
|
Nach der umfangreichen Einführung in GTK+ zuvor haben Sie sicherlich etwas Komplizierteres als das Listing und die Erläuterungen hier erwartet. Es kommt noch besser. Wenn Sie das Beispiel verstanden haben, ist der Rest des Kapitels und der Rest von GTK+ eigentlich nur noch »Formsache«, da der Vorgang immer ähnlich wie im Beispiel eben abläuft (abgesehen davon, dass Sie in diesem Listing noch keine Widgets packen mussten).
15.5.1 Dialogfenster (Dialogboxen)
Abgeleitet von der Klasse GtkWindow gibt es noch die Fensterklasse GtkDialog. Das ist ein Widget für ein Dialogfenster, das gewöhnlich dazu verwendet wird, dem Anwender etwas Wichtiges mitzuteilen oder ihn abzufragen. Das folgende Listing ist eine Erweiterung des ersten Beispiels. Hinzugefügt wurde gegenüber dem Beispiel zuvor eine Abfragefunktion in Form eines einfachen Dialogfensters, das aufpoppt, wenn der Anwender das (Haupt-)Fenster schließen (zerstören) will. Eine übliche »Sind Sie sicher?«-Abfrage.
/* gkt1b.c */
/* Ein leeres Fenster und eine Dialogbox */
#include <gtk/gtk.h>
static GtkWindow *win;
static gint
delete_Event(GtkWidget * widget, GdkEvent event, gpointer daten){
GtkWidget *dialog, *label;
gint result;
/* Eine neue Dialogbox erzeugen */
dialog = gtk_dialog_new_with_buttons (
"Sind Sie sicher?",
win,
GTK_DIALOG_DESTROY_WITH_PARENT,
"Ja", GTK_RESPONSE_ACCEPT,
"Nein", GTK_RESPONSE_REJECT,
NULL);
/* Ein Label dazu */
label = gtk_label_new (
"Wollen Sie das Programm wirklich beenden?");
/* Label in die vorhandene (Standard-)Box (vertikal) */
/* von der Dialogbox packen */
gtk_container_add( GTK_CONTAINER( GTK_DIALOG( dialog )->vbox),
label);
/* Dialogbox anzeigen */
gtk_widget_show_all (dialog);
/* Wartet auf eine Eingabe in der Dialogbox des Anwenders */
result = gtk_dialog_run (GTK_DIALOG (dialog));
switch (result) {
case GTK_RESPONSE_ACCEPT: /* Ja-Button wurde gedrückt */
g_print("GTK_RESPONSE_ACCEPT\n");
/* Dialogbox zerstören */
gtk_widget_destroy (dialog);
/* Hauptfenster auch zerstören */
return FALSE;
break;
case GTK_RESPONSE_REJECT:
g_print("GTK_RESPONSE_REJECT\n");
/* Dialogbox zerstören */
gtk_widget_destroy (dialog);
/* Hauptfenster nicht zerstören */
return TRUE;
break;
case GTK_RESPONSE_DELETE_EVENT:
g_print("GTK_RESPONSE_DELETE_EVENT\n");
/* Dialogbox zerstören */
gtk_widget_destroy (dialog);
/* Hauptfenster nicht zerstören */
return TRUE;
break;
default:
g_print("Fehler beim Auswerten der Dialogbox?\n");
return TRUE;
}
}
static void end (GtkWidget * widget, gpointer daten) {
g_print ("Und tschuess!\n");
/* Die Verarbeitungsschleife beenden */
gtk_main_quit ();
}
int main (int argc, char **argv) {
/* 1. Die Umgebung initialisieren */
gtk_init (&argc, &argv);
/* 2. Die Widgets erzeugen */
/* 2a. Fenster mit den folgenden 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, NULL);
/* 3. Signalhandler (Callback-Funktion) einrichten */
g_signal_connect ( win, "delete-event",
G_CALLBACK (delete_Event), NULL );
g_signal_connect ( win, "destroy",
G_CALLBACK (end), NULL );
/* 4. Hier gibt es noch nichts zum Packen */
/* 5. (Widgets-)Fenster anzeigen */
gtk_widget_show_all (GTK_WIDGET (win));
/* 6. Hauptschleife von gtk-Verarbeitungsschleife */
gtk_main ();
g_print ("Die GTK-Hauptschleife wurde beendet\n");
return 0;
}
Das Programm bei der Ausführung:
$ gcc -Wall -o gtk1b gtk1b.c \
`pkg-config gtk+-2.0 --cflags --libs`
$ ./gtk1b
Zum Erstellen eines neuen Dialogfensters wurde hier die Funktion gtk_dialog_new_with_buttons() verwendet. Zwar wäre auch hier der Weg über g_object_new() möglich gewesen, nur wäre es in diesem Fall (ausnahmsweise) nicht so komfortabel wie mit gtk_dialog_new_with_buttons(). Die Funktion besitzt folgende Syntax:
GtkWidget* gtk_dialog_new_with_buttons(
const gchar *title,
GtkWindow *parent,
GtkDialogFlags flags,
const gchar *first_button_text, ...);
Mit dem ersten Parameter können Sie den Titel des Dialogfensters angeben. Als zweiter Parameter wird das Elternfenster verwendet – quasi das Fenster, welches das Dialogfenster erzeugt hat. Jetzt werden noch einige Flags benötigt (dritter Parameter), wovon Sie folgende zur Auswahl haben:
|
GTK_DIALOG_MODAL – Wie schon beim gewöhnlichen Fenster können Sie auch hier ein modales Fenster erzeugen (wovon allerdings in der Praxis immer abzuraten ist). |
|
GTK_DIALOG_NO_SEPARATOR – Hiermit können Sie den Trennbalken (Separator) über den Buttons in der vertikalen Box entfernen. |
|
GTK_DIALOG_DESTROY_WITH_PARENT – Mit dem Setzen dieses Flags gehen Sie sicher, wenn sich das Elternfenster noch vor dem Dialogfenster beendet, dass das Dialogfenster auch zerstört wird. |
Mit den letzten Parametern können Sie eine variable Buttonliste angeben, die abwechselnd aus der Beschriftung des Buttons und einer Antwortkennung vom Typ gint für den Button besteht. Theoretisch können Sie für diese Antwortkennung eine beliebige positive Ganzzahl verwenden. In der Praxis wird hierbei allerdings gewöhnlich auf eine der vordefinierten Konstanten zurückgegriffen. Wird im Dialogfenster ein Button geklickt, wird das Signal response emittiert. Theoretisch könnten Sie hier auch eine Callback-Funktion einrichten, die wie folgt aussieht:
void dialog_callback( GtkDialog *dlg, gint resp, gpointer data)
Im zweiten Parameter würden Sie dann die Antwortkennung vorfinden, die response emittiert hat. Folgende vordefinierte Konstanten sind für die Antwortkennung (Kennungs-ID) dabei schon vergeben:
|
GTK_RESPONSE_DELETE_EVENT – Dies wird zurückgegeben, wenn das Dialogfenster über dem Fenstermanager geschlossen wird. Hierbei wird das übliche delete-event-Signal emittiert. |
|
GTK_RESPONSE_NONE – Wurde das Dialogfenster vom Programm entfernt, wird diese Kennung zurückgegeben. |
Die weiteren Konstanten sind Kennungen, die im Gegensatz zu den beiden eben erwähnten Konstanten keine besondere Bedeutung haben und nur dem Komfort dienen:
|
GTK_RESPONSE_ACCEPT – Annehmen |
|
GTK_RESPONSE_REJECT – Ablehnen |
|
GTK_RESPONSE_OK – O. k. |
|
GTK_RESPONSE_CANCEL – Abbrechen |
|
GTK_RESPONSE_CLOSE – Schließen |
|
GTK_RESPONSE_YES – Ja |
|
GTK_RESPONSE_NO – Nein |
|
GTK_RESPONSE_HELP – Hilfe |
Da im Beispiel keine Callback-Funktion mit g_signal_connect() eingerichtet wurde, wird die Funktion gtk_dialog_run() verwendet:
gint gtk_dialog_run (GtkDialog *dialog);
Diese Funktion blockiert so lange in einer rekursiven Schleife, bis das Dialogfenster ein empfangenes (response) Signal emittiert oder das Fenster zerstört wird. Wird das Dialogfenster während der Ausführung von gtk_dialog_run() zerstört, wird GTK_RESPONSE_NONE zurückgegeben. Ansonsten wird die Kennungs-ID (wurden eben beschrieben) vom response-Signal zurückgegeben. Beachten Sie bitte, dass in der rekursiven Schleife die Funktion gtk_widget_show() verwendet wird. Würden Sie im Beispiel nicht
gtk_widget_show_all (dialog);
verwenden, würde das Dialogfenster zwar trotzdem angezeigt, allerdings ohne seine Kinder-Widgets (im Beispiel ohne das Text-Label)!
Im Listing wurde auch ein Text-Label erzeugt und in die Box des Dialogfensters gepackt. Genaueres zu diesen beiden Widgets erfahren Sie noch ausführlicher. Natürlich können Sie hierbei jedes beliebige Widget in das Dialogfenster packen, da es sich ja hierbei auch um eine abgeleitete Klasse von GtkWindow handelt.
15.5.2 GtkMessageDialog
GtkMessageDialog ist wiederum eine abgeleitete Klasse von GtkDialog und somit auch abgeleitet von GtkWindow. Der Vorteil von GtkMessageDialog ist, dass sich hiermit noch einfacher und schneller einige Hinweis-Dialoge zusammenbasteln lassen. Wobei man dazu gleich erwähnen muss, dass diese Klasse im Funktionsumfang sehr eingeschränkt ist und man kaum mehr als einfache Ja-/Nein-Buttons erstellen kann. Somit ist diese Klasse nur beschränkt für den Praxisgebrauch geeignet.
|