Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Linux, Systemprogrammierung C C++ C/C++ ANSI C Linux Windows GUI gtk gtk+ Gimp Toolkit Fenster Signale Callbacks GUI gtk gtk+ Gimp Toolkit Fenster Signale Callbacks Das Konzept von gtk+

Signale und Callbacks           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Um mit GTK zu Programmieren ist es unbedingt notwendig, das Konzept davon zu verstehen. Aber keine Angst es ist einfacher als Sie denken.

Ein GTK-Programm initialisiert sich erst mal selbst (mit gtk_init()), arbeitet anschließend das ganze Programm iterativ bis zur Funktion gtk_main() ab. Und das war's dann erst mal. Nun wartet das Programm in der gtk_main() Funktion auf eine Ereignis. Man kann nun sagen das Programm schläft oder ist in einer Endlosschleife. Tritt ein Ereignis auf, arbeitet GTK das Ereignis ab und springt, wenn fertig, wieder zu gtk_main() Funktion zurück. Außer bei diesem Ereignis handelt es sich um gtk_main_quit(), welches das GTK-Programm beendet. Hierzu der Programmablauf eines GTK - Programms grafisch ...

Nun wissen Sie wie ein GTK-Programm abläuft. Als nächstes müssen Sie nur noch wissen, wie Sie mit GTK ein Ereignis abfragen können und vor allem wie Sie auf ein Ereignis reagieren können.

Und dies ist noch einfacher als man glaubt. Dazu müssen Sie nur für ein Widget einen Signalhandler mit einer entsprechende Callback-Funktion einrichten.

In der Praxis läuft dies folgendermaßen ab. Nehmen wir mal an, Sie erzeugen als Widget einen Button (Knopf). Für diesen Knopf richten Sie jetzt einen Signalhandler ein mit einer Callback-Funktion. Nun drückt der Anwender den Button. Sofort wird ein entsprechendes Signal an die gtk_main()-Funktion geschickt. Jetzt wird nachgesehen, welche oder ob eine Callback-Funktion für diese Widget eingerichtet wurde. Danach wird diese Callback-Funktion ausgeführt. Zum Schluß springt das Programm wieder in die gtk_main()-Schleife (sofern nicht die Funktion gtk_main_quit() aufgerufen wurde).

Es dürfen aber durchaus mehr als ein Ereignis pro Widget verwendet werden. In diesem Fall werden die einzelnen Ereignisse, in der Reihenfolge ihrer Initialisierung, aufgerufen.

Einige dieser Signal generiert GTK selbst. Andere wiederum werden im X-Window-System generiert.

Jetzt benötigen Sie eine Funktion, mit der Sie einen Signalhandler für ein Widget registrieren können. Hier die Funktion dazu ...

gint gtk_signal_connect(GtkObject *object, gchar *name,
                        GtkSignalFunc func, gpointer func_data);

Hier wird ein Zeiger für ein GtkObjekt (Widget) übergeben. Wobei für GtkObject wieder ein Casting gemacht werden muss. Für name geben wir den Namen des Ereignishandler an. Dies könnte zum Beispiel sein ...

Davon gibt es noch ein Menge mehr Ereignisse, worauf wir aber, wie schon erwähnt, in den Programmen zu sprechen kommen.

Der Dritte Parameter der Funktion gtk_signal_connect(), ist ein Zeiger auf eine Callback-Funktion. Mit dem letzten Parameter können wir der Callback-Funktion noch Daten mitgeben, oder NULL für keine Daten.

Jetzt werden Sie sich fragen, wie eine solche Callback-Funktion überhaupt auszusehen hat? Nehmen wir an, wir haben unsere Callback-Funtkion folgendermaßen registriert ...

gtk_signal_connect(GTK_OBJECT(fenster), "destroy_event",
                   GTK_SIGNAL_FUNC(my_callback), NULL);

Wir richten hier für das Widget fenster einen Ereignishandler destroy_event für das löschen des Widets ein. Als Callback-Funktion wird die Funktion my_callback ohne Daten aufgerufen. Nun wollen wir die Funktion my_callback ansehen ...

void my_callback(GtkWidget *widget, gpointer data)
{
 g_print("Ende");
 gtk_main_quit();
}

Das widget ist logischerweise ein Zeiger auf das Widget welches das Signal ausgelöst hat. Die Callback-Funktion beendet das GTK-Programm mit der Funktion gtk_main_quit().

Ein zweite Möglichkeit, eine Callback-Funktion für ein bestimmtes Signal einzurichten, wäre mit der Funktion ...

gint gtk_signal_connect_object(GtkObject *object, gchar *name,
                               GtkSignalFunc func, GtkObjekt *slot_object);

Damit ist es zum Beispiel möglich, für ein Widget eine Callbackfunktion für ein anderes Widget aufzurufen. Simples Beispiel ...

gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                          GTK_SIGNAL_FUNC(my_callback), GTK_OBJECT(fenster));

Hiermit wird Beispielsweise, wenn das Widget button angeklickt wurde, die Callbackfunktion my_callback aufgerufen, welche sich aber auf das Widget fenster bezieht. Keine Sorge, davon werden Sie noch genug in der Praxis sehen.

Nun haben sie das Konzept von GTK kennen gelernt. Jetzt wollen wir im nächsten Beispiel zur Tat schreiten und mit unserem "Hallo Welt" Programm beginnen.

Hallo Welt in gtk+           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Nun wollen wir in diesem Kapitel ein Fenster erstellen mit einem Button, mit "Hallo Welt"-Beschriftung. Bei einem Klick auf diesem Button wird das Fenster wieder geschlossen. Sie werden zum ersten mal sehen wie Sie Signale in der Praxis einrichten können, und wie Sie damit umgehen können.

Genug der Reden, sehen wir uns dazu das Programm an ...

#include <gtk/gtk.h>

gint delete_cb(GtkWidget *widget, GdkEvent *event, gpointer *data)
{
 return(TRUE);
}

void ende_cb(GtkObject *object)
{
 gtk_main_quit();
}


int main(int argc, char **argv)
{
 GtkWidget *fenster;
 GtkWidget *button;
 /*Gtk initialisieren*/
 gtk_init(&argc, &argv);
 /*Ein neues Fenster erstellen*/
 fenster = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 /*Einen Button erstellen*/
 button  = gtk_button_new_with_label("Hallo Welt");

 /*Signale registrieren*/
 gtk_signal_connect(GTK_OBJECT(fenster), "delete_event",
                    GTK_SIGNAL_FUNC(delete_cb),NULL);
 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                           GTK_SIGNAL_FUNC(ende_cb), GTK_OBJECT(fenster));
 /*Fenstertitel*/
 gtk_window_set_title(GTK_WINDOW(fenster), "Hallo Welt mit Button");
 /*Fensterposition*/
 gtk_window_set_position(GTK_WINDOW(fenster),GTK_WIN_POS_CENTER);

 gtk_container_set_border_width(GTK_CONTAINER(fenster),25);
 /*Fenster dem dem Button zuordnen*/
 gtk_container_add(GTK_CONTAINER(fenster),button);
 /*Zeigs uns.....*/
 gtk_widget_show_all(fenster);

 gtk_main();

 return 0;
}

Wenn Sie diese Programm wie gewohnt aus dem Kapitel der Fenster übersetzen, könnte es wie folgt aussehen ...

Nun wollen wir das Beispiel ein wenig analysieren. Es Interessieren uns vorerst nur die Ereignisse und Ihre Reaktionen.

Zuerst zu unserem ersten Ereignishandler den wir eingerichtet haben ...

gtk_signal_connect(GTK_OBJECT(fenster), "delete_event",
                   GTK_SIGNAL_FUNC(delete_cb),NULL);

Das Ereignis "delete_event" wird vom Window-Manager an das Programm gesendet, wenn wir das "Fenster schließen" drücken. Dies ignorieren wir aber, da unser Callback-Funktion delete_cb() als Rückgabewert TRUE liefert. Würden wir FALSE angeben, würde das Fenster geschlossen. Mit dem zweiten Siganlhandler ...

gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                          GTK_SIGNAL_FUNC(ende_cb), GTK_OBJECT(fenster));

... reagieren wir, wenn der Button ge"clicked" wurde, mit der Callback-Funktion ende_cb(). Die Callback-Funktion wirkt sich anschließend auf das Widget fenster aus. Unsere Callback-Funktion ende_cb() schließt das Fenster (mit gtk_main_quit()). Die Callback-Funktion ende_cb() hätten wir uns aber mit folgender Schreibweise ersparen können ...

gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                          GTK_SIGNAL_FUNC(gtk_main_quit), GTK_OBJECT(fenster));

Hier haben wir die Callback-Funktion gleich direkt registriert. Bildlich können Sie sich denn Programmablaufplan "Hallo Welt" folgendermaßen vorstellen ...

Den Rest des Programms werden wir in den nächsten Kapiteln durchnehmen.

Weiter mit Packing Widgets (vertiakl und horizontal)