Seitenleiste

Einfache Texteingabe

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.

Ein Entry erstellen

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!

Signale verknüpfen

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

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.

Das fertige Programm

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:

GtkEntry

Außerdem sollte nach Klick auf „Eingabe“ das GtkLabel den zuvor eingegebenen Text im GtkEntry anzeigen. Wie zu sehen lassen sich mit GtkEntrys 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!

Ausblick

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.

zurück || hoch zur Startseite || weiter

1)
Eine Übersicht über solche (oft sehr nützlichen) String-Funktionen der GLib findet sich in der GLib-Referenz
2)
natürlich nur, wenn dies notwendig ist