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.13 Events  toptop

Die Einführung in GTK+ ist fast zu Ende, und es wurde kaum ein Wort über Events und deren Bearbeitung erwähnt. Sie haben bisher immer Ihre GTK+-Anwendungen erstellt und sich beim Einrichten der Callback-Funktion das ausgesucht, was Sie benötigt haben (clicked, activate ...), das war’s. Mehr ist im Prinzip eigentlich auch gar nicht nötig, wenn Sie mit GTK+ Programme schreiben wollen. Die Events in GTK+ werden mit Wrapper von den GDK-Events verwendet und machen Ihnen das Leben recht einfach. GTK+ übernimmt alles für Sie. Die GDK-Events sind in der GTK+Bibliothek als Signale vorhanden. In der Regel könnten Sie es also dabei belassen und so weiterarbeiten.

Was ist aber, wenn Sie z. B. bei einem Mausklick im Fenster die exakte Position benötigen, wo und welcher Mausbutton gedrückt wurde – wie bei einem Zeichenprogramm? Sie haben zwar dafür die Signale button-press-event, button-release-event oder clicked, aber keine genaue Positionsangaben. In solch einem Fall müssen Sie tatsächlich ein wenig in die niedrigere Ebene von GDK einsteigen. In diesem Fall geht es zwar vorwiegend um die Maus-Events. Aber wenn das Thema verstanden wurde, lässt sich dieses genauso gut auf die anderen Events übertragen.

Sie haben häufig in Callback-Funktionen den Parameter (genauer die Struktur) GdkEvent verwendet, ohne eigentlich gewusst zu haben, was Sie da eigentlich nutzen. Im Prinzip konnte Ihnen das auch egal sein, da Ihnen ja GTK+ die ganze Arbeit abgenommen hat. Ein Beispiel einer solchen Callback-Funktion:

gboolean
callback(GtkWidget * widget, GdkEvent* event, GtkWidget * label);

Es wird jetzt davon ausgegangen, dass ein Mausbutton an einer bestimmten Position im Fenster betätigt wurde und die Callback-Funktion show_pos mit dem Signal button-press-event aufgerufen wurde. Jetzt benötigen Sie erst die Struktur von GdkEvent. Da in der Regel nur ein Event auf einmal auftritt, wird hierzu eine union verwendet:

union GdkEvent {
  GdkEventType              type;
  GdkEventAny               any;
  GdkEventExpose            expose;
  GdkEventNoExpose          no_expose;
  GdkEventVisibility        visibility;
  GdkEventMotion            motion;
  GdkEventButton            button;
  GdkEventScroll            scroll;
  GdkEventKey               key;
  GdkEventCrossing          crossing;
  GdkEventFocus             focus_change;
  GdkEventConfigure         configure;
  GdkEventProperty          property;
  GdkEventSelection         selection;
  GdkEventProximity         proximity;
  GdkEventClient            client;
  GdkEventDND               dnd;
  GdkEventWindowState       window_state;
  GdkEventSetting           setting;
};

In dieser union finden Sie jetzt alle möglichen Event-Strukturen, die bei einer Anwenderaktion zurückgegeben werden können. In diesem Fall interessiert uns das Event der Mausbuttons, das Sie an GdkEventButton erkennen können. Die Spur soll nun weiterverfolgt werden. Ein Blick in die Dokumentation bringt folgende Struktur ans Tageslicht:

struct GdkEventButton {
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  guint32 time;
  gdouble x;
  gdouble y;
  gdouble *axes;
  guint state;
  guint button;
  GdkDevice *device;
  gdouble x_root, y_root;
};

Und schon haben Sie alles, was Sie für die Event-_Bearbeitung der Maus benötigen. Im Großen und Ganzen sind wir hier ja nur an x, y und button interessiert – aber ein wenig Weiterbildung kann nicht schaden. type beinhaltet die Art des Mausereignisses (GDK_BUTTON_PRESS, GDK_2BUTTON_PRESS (Doppelklick), GDK_3BUTTON_PRESS (Dreifachklick) oder GDK_BUTTON_RELEASE. window ist das Fenster, welches das Event erhalten hat. time enthält die Zeit des Events in Millisekunden. x und y sind die relativen Koordinaten des Mauszeigers im Fenster. Mit axes werden die x-, y-Achsen des Gerätes übersetzt. Im Falle einer Maus ist der Wert NULL. state ist eine Bitmaske, die den Zustand der modifizierten Tasten (wie (Ctrl), (Ş)oder (Alt)) und den Zeigerbutton anzeigt. Welche Maustaste gedrückt wurde, finden Sie in button. Der Wert wird von 1 bis 5 nummeriert und entspricht denselben Werten wie schon beim X Window. device macht eine Aussage zum Gerät, welches das Event ausgelöst hat (es muss nicht immer eine Maus sein). x_root und y_root sind relative Koordinaten des Zeigers vom Ursprung des Bildschirms.

Somit ergibt sich folgende Callback-Funktion:

gboolean show_pos ( GtkWidget * widget,
                    GdkEvent * event,
                    GtkWidget * label );

Wollen Sie jetzt hier ermitteln, welcher Button gedrückt wurde, können Sie dies mit folgender Angabe machen:

gint z = event->button.button;

event ist der Zeiger auf die Struktur GdkEvent in der Callback-Funktionsdefinition, button ist vom Typ GdkEventButton in union GdkEvent, und der zweite button ist eine Strukturvariable in GdkEventButton. Sie können dies aber abkürzen, indem Sie bei dem Funktionsprototypen der Callback-Funktion gleich GdkEventButton verwenden:

static gboolean show_pos ( GtkWidget * widget,
                           GdkEventButton * event, 
                           GtkWidget * label );

Der Rückgabewert der Callback-Funktion sollte TRUE sein, wenn alles beim Behandeln des Events glatt verlief – bei einem Fehler sollten Sie FALSE zurückgeben.

Wie schon mit dem Xt-Toolkit müssen Sie die Events, die Sie bearbeiten wollen, selektieren – denn auch hier macht es wenig Sinn, von vornherein auf alle Events reagieren zu wollen. Der X-Server wäre nur noch mit den Events beschäftigt. Die Events, die Sie speziell bearbeiten wollen, selektieren Sie mit der Funktion gtk_widget_set_event(). Die Syntax dazu:

void gtk_widget_set_events (GtkWidget *widget,  gint events);

Damit fügen Sie zu einem Widget eine oder mehrere Eventmasken hinzu, die Sie bearbeiten wollen. Mehrere Masken werden mit dem bitweisen ODER-Operator getrennt. Hierzu einige der wichtigsten GDK-Eventmasken:


Tabelle 15.29    Einige Eventmasken und deren Signale

Eventmaske Signal Bedeutung
GDK_EXPOSURE_MASK expose-event Fenster oder Teil davon wurde sichtbar.
GDK_BUTTON_MOTION_MASK motion-notify-event Maus wurde bewegt, während gleichzeitig ein Button gedrückt wurde.
GDK_BUTTON1_MOTION_MASK GDK_BUTTON2_MOTION_MASK GDK_BUTTON3_MOTION_MASK motion-notify-event Maus wurde bewegt, während gleichzeitig ein spezieller Button gedrückt wurde.
GDK_BUTTON_PRESS_MASK button-press-event Button wird gedrückt.
GDK_BUTTON_RELEASE_MASK button-release-event Button wird losgelassen.
GDK_KEY_PRESS_MASK key-press-event Taste wird gedrückt.
GDK_KEY_RELEASE_MASK key-release-event Taste wird losgelassen.
GDK_ENTER_NOTIFY_MASK enter-notify-event Zeiger ist in das Fenster gekommen.
GDK_LEAVE_NOTIFY_MASK leave-notify-event Zeiger hat das Fenster verlassen.
GDK_FOCUS_CHANGE_MASK focus-in-event focus-out-event Tastaturfokus zwischen den Fenstern wurde gewechselt.
GDK_PROPERTY_CHANGE_MASK property-notify-event Eine Fenstereigenschaft wurde verändert.

Hierzu nun ein einfaches Beispiel, das sich vorwiegend um die Events GDK_BUTTON_PRESS_MASK und GDK_BUTTON_RELEASE_MASK kümmert, aber auch die Eventmasken GDK_ENTER_NOTIFY_MASK, GDK_LEAVE_NOTIFY_MASK und GDK_KEY_PRESS_MASK verwendet, ohne allerdings Wichtigeres damit zu machen.

/* gtk9.c */
#include <gtk/gtk.h>
#define LEFTBUT   1
#define MIDDLEBUT 2
#define RIGHTBUT  3
static gint
delete_Event(GtkWidget *widget, GdkEvent *event, gpointer data) {
  return FALSE;
}
static void exitCB (GtkButton * clicked, gpointer data) {
  gtk_main_quit ();
}
static gboolean show_pos (
  GtkWidget *widget, GdkEventButton *event, GtkWidget *label ) {
  const gchar *button[] = {
     NULL, "linker Button", "mittlerer Button","rechter Button"
   };
  gint x = event->x;
  gint y = event->y;
  gint z = event->button;
  gchar *pos = g_strdup_printf ("Event: %d, %d (%s)\n",
                  x, y, button[z]);
  gtk_label_set_text (GTK_LABEL (label), pos);
  return TRUE;
}
static gboolean change_label1 ( 
  GtkWidget* widget, GdkEventButton* event, GtkWidget *label ) {
  const gchar *new_label = {
     "Event : Mauscursor tritt ins Fenster ein\n" 
  };
  gtk_label_set_text (GTK_LABEL (label), new_label);
  return TRUE;
}
static gboolean change_label2 ( 
 GtkWidget * widget, GdkEventButton * event, GtkWidget * label) {
  const gchar *new_label = {
     "Event : Mauscursor hat Fenster verlassen\n" 
   };
  gtk_label_set_text (GTK_LABEL (label), new_label);
  return TRUE;
}
static gboolean key_press ( 
  GtkWidget * widget, GdkEventKey * event, GtkWidget * label) {
  gchar *new_label = g_strdup_printf (
     "Event : Taste '%s' (Wert:%d) wurde gedrueckt\n",
     event->string, event->keyval);
  gtk_label_set_text (GTK_LABEL (label), new_label);
  return TRUE;
}
int main (int argc, char **argv) {
  GtkWidget *fenster;
  GtkWidget *label;
  /*Gtk initialisieren */
  gtk_init (&argc, &argv);
  /*Ein neues Fenster erstellen */
  fenster = g_object_new( GTK_TYPE_WINDOW,
                         "title", "Verschiedene Anzeigeelemente",
                         "default-width",  300,
                         "default-height", 200,
                         "resizable", TRUE,
                         "window-position", GTK_WIN_POS_CENTER,
                         "border-width", 5,
                         NULL );
  label = g_object_new( GTK_TYPE_LABEL, NULL);
  /* Versuch, über den Window-Manager zu beenden */
  g_signal_connect ( GTK_OBJECT (fenster), "delete-event",
                     G_CALLBACK (delete_Event), NULL);
  g_signal_connect ( GTK_OBJECT (fenster), "destroy",
                     G_CALLBACK (exitCB), NULL);
  /* Callbacks für die Events einrichten */
  g_signal_connect (GTK_OBJECT (fenster), "button-press-event",
                    G_CALLBACK (show_pos), label);
  g_signal_connect ( GTK_OBJECT (fenster), "enter-notify-event",
                     G_CALLBACK(change_label1), label);
  g_signal_connect ( GTK_OBJECT (fenster), "leave-notify-event",
                     G_CALLBACK (change_label2), label);
  g_signal_connect ( GTK_OBJECT (fenster), "key-press-event",
                     G_CALLBACK (key_press), label);
  gtk_widget_set_events (fenster,
             GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
           | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
           | GDK_KEY_PRESS_MASK);
  gtk_container_add (GTK_CONTAINER (fenster), label);
  /* Zeigs uns ... */
  gtk_widget_show_all (fenster);
  gtk_main ();
  return 0;
}

Das Programm bei der Ausführung:

$ gcc -Wall -o gkt9 gtk9.c `pkg-config gtk+-2.0 --cflags --libs`
$ ./gkt9

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

Abbildung 15.19    GDK-Events


 << 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