====== 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 [[gui:gtk:signals|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 [[:c:var:visibility#globale_variablen|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. ((Eine Übersicht über solche (oft sehr nützlichen) String-Funktionen der GLib findet sich in der [[http://library.gnome.org/devel/glib/stable/glib-String-Utility-Functions.html|GLib-Referenz]])) **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 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:\\ {{:gui:gtk:screen.jpg|GtkEntry }} 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 ((natürlich nur, wenn dies notwendig ist)), 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.
**[[ gui:gtk:signals |zurück]] || [[gui:gtk:start|hoch zur Startseite]] || [[ gui:gtk:dialogs |weiter]]**
====== ====== ---- [[http://forum.proggen.org/viewtopic.php?f=39&t=847|Autorendiskussion]]