Oft ist es nötig, Texteingaben vom User abzufragen. GTK stellt für einzeilige Texteingaben das GtkEntry
zur Verfügung. Es kann zum Beispiel benutzt werden, um den Namen des Users abzufragen. Wir wollen in dieser Lektion ein GtkEntry
erstellen und den Text daraus abfragen.
Dies ist nicht viel schwieriger als bei den schon bekannten Widgets. Da wir unser Beispiel aus den letzten Lektionen fortführen, können wir uns einige Dinge ersparen. Zum Erstellen des Entry deklarieren wir erst einmal einen Zeiger auf ein GtkWidget
:
GtkWidget *textentry;
Um textentry
mit Inhalt zu füllen gibt es wieder eine „new“ Funktion:
textentry = gtk_entry_new();
Soweit, so gut. Packen wir es in die Box:
gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
Und schon habt ihr euer erstes GtkEntry
erstellt!
Als nächstes möchten wir unsere Anwendung „zum Leben erwecken“. Doch was soll sie tun?
Bei einem Klick auf den Button soll der Inhalt des Entrys auf das Label übertragen werden.
Klingt einfach. Doch haben wir nun schon ein Problem. Wenn wir nämlich ein Signal verknüpfen, können wir der Callback Funktion nur das Auslöser-Widget und ein weiteres Widget übergeben. In unserem Beispiel müssten wir allerdings zwei Widgets übergeben (das GtkLabel
und das GtkEntry
). Wie lösen wir dieses Problem?
Zuerst deklarieren wir eine globale Variable:
char *text = NULL;
Damit dieser Wert gleich am Anfang im GtkLabel
steht, ändern wir unser Beispiel von vorhin etwas ab.\
Statt:
label = gtk_label_new("Klick auf den Button!");
schreiben wir:
label = gtk_label_new("Gib etwas ein!");
Um das Problem mit den Signalen zu umgehen, verknüpfen wir unseren Button zweimal:
g_signal_connect(button, "clicked", G_CALLBACK(change_text), textentry); g_signal_connect(button, "clicked", G_CALLBACK(change_label), label);
Hinweis: Die Reihenfolge, in der die Callbacks registriert werden, entscheidet, welche Callback Funktion zuerst ausgeführt wird.
Bei der ersten Callback Funktion (change_text
) wird der Inhalt des Entrys auf unsere globale Variable zugewiesen. Danach kann mit der schon vorhandene Methode change_label
der Text des Labels geändert werden. So sieht die change_text
Methode aus:
void change_text(GtkButton *trigger, gpointer textentry) { g_free (text); text = g_strdup(gtk_entry_get_text(GTK_ENTRY(textentry))); }
Mit gtk_entry_get_text(GTK_ENTRY(textentry))
bekommen wir den Text des GtkEntry
s.
Allerdings hält das GtkEntry
diesen Zeiger selbst, wir wissen nicht, wann der Speicherplatz freigegeben wird.
Aus diesem Grund kopieren wir den Inhalt des Strings Zeichen für Zeichen in einen neuen Speicherbereich, den wir verwalten. Diese Aufgabe erledigt g_strdup
für uns. 1)
Wichtig: g_strdup
alloziert Speicher, den wir freigeben müssen. Dafür stellt die GLib g_free bereit, welches equivalent zu free aus C-Standard Library arbeitet. Ist der Zeiger NULL, macht g_free nichts
. Aus diesem Grund passiert bei ersten Aufruf des Callbacks nichts, erst beim zweiten wird Speicher freigegeben.
Desweiteren müssen wir nach gtk_main
unseren String endgültig mit g_free
freigeben!
Als nächstes kommt die leicht veränderte change_label
Funktion:
void change_label(GtkButton *trigger, gpointer label) { gtk_label_set_text(GTK_LABEL(label), text); }
Hier hat sich nur das zweite Argument der gtk_label_set_text
geändert, da wir den Inhalt unserer globalen Variable benutzen wollen.
Zur besseren Übersicht nun noch einmal der vollständige Quelltext:
#include <gtk/gtk.h> char *text = NULL; void change_label(GtkButton *trigger, gpointer label) { gtk_label_set_text(GTK_LABEL(label), text); } void change_text(GtkButton *trigger, gpointer textentry) { g_free (text); text = g_strdup(gtk_entry_get_text(GTK_ENTRY(textentry))); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *label; GtkWidget *button; GtkWidget *textentry; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); vbox = gtk_vbox_new(FALSE, 10); gtk_container_add(GTK_CONTAINER(window), vbox); label = gtk_label_new("Gib etwas ein!"); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); textentry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0); button = gtk_button_new_with_label("Eingabe"); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(button, "clicked", G_CALLBACK(change_text), textentry); g_signal_connect(button, "clicked", G_CALLBACK(change_label), label); gtk_widget_show_all(window); gtk_main(); g_free (text); return 0; }
Sollte kompiliert und ausgeführt in etwa so aussehen:
Außerdem sollte nach Klick auf „Eingabe“ das GtkLabel
den zuvor eingegebenen Text im GtkEntry
anzeigen.
Wie zu sehen lassen sich mit GtkEntry
s Benutzereingaben leicht verwalten. Wichtig ist nur, dass die erhaltenen Strings (aus gtk_entry_get_text
) mit g_strdup()
in einen eigenen Speicherbereich kopiert werden müssen 2), der dann auch wieder freigegeben werden sollte!
Und wieder kommt eine Lektion dem Ende entgegen. Das GtkEntry
ist das primitivste aller in GTK verfügbaren Widgets zur Texteingabe. Für mehrzeilige Texteingabe + Formatierung gibt es GtkTextView
, was aber später ein Thema sein wird.