15.12 Auswählen (Selection)
Dinge wie das Auswählen (Selektieren) einer Datei, der Farben oder Schriftarten muss man zum Glück nicht mehr selbst programmieren. Hierzu existieren in GTK+ wieder einige vorbereitete Widgets. Zur einfachen Farbauswahl wird das Widget GtkColorSelection, zur Auswahl von Schriftarten GtkFontSelection und zur Dateiauswahl GtkFileSelection verwendet.
Auf die Auswahl von Dateien soll in diesem Abschnitt etwas näher eingegangen werde. Hierzu wurde das Listing des einfachen Texteditors vom Beispiel zuvor um die Funktion der Dateiauswahl erweitert. Damit können Sie nun einfache Textdateien öffnen und im Editor anzeigen lassen. Zusätzlich wurde dem Beispiel auch noch eine Funktion zum Speichern spendiert, wobei hier wiederum einige weitere Funktionen des Text-Widget-Systems von GTK+ verwendet wurden.
/* gtk8.c */
/* Mehrzeiliger Text */
/* mit Dateiauswahl - GtkFileSelection */
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
/* Funktionsprototypen */
static GtkWindow *create_window (void);
static void create_tags (GtkTextBuffer * buffer);
static void on_button_clear_clicked (
GtkButton * button, gpointer user_data );
static void on_button_cut_clicked (
GtkButton * button, gpointer user_data );
static void on_button_copy_clicked (
GtkButton * button, gpointer user_data );
static void on_button_paste_clicked (
GtkButton * button, gpointer user_data );
static void on_button_bold_clicked (
GtkButton * button, gpointer user_data );
static void on_button_underline_clicked (
GtkButton * button, gpointer user_data );
static void on_button_strike_clicked (
GtkButton * button, gpointer user_data );
static void on_button_color_clicked (
GtkButton * button, gpointer user_data );
static void ok_buttonCB (
GtkWidget * clicked, GtkWidget * selection);
static void file_open (
GtkButton * clicked, GtkWidget * selection);
static void on_button_save_clicked (
GtkButton * button, gpointer user_data );
/* Dateiname zum Öffnen */
static gchar *file = NULL;
static GtkTextView *textview;
static GtkWindow * create_window (void) {
GtkWindow *window;
GdkPixbuf *pic;
GtkVBox *vbox_main;
GtkToolbar *toolbar;
GtkWidget *button_clear, *button_cut, *button_copy,
*button_paste, *button_bold, *button_underline,
*button_strike, *button_color, *button_open,
*button_save;
GtkScrolledWindow *scrolledwindow;
GtkTextBuffer *buffer;
GtkFileSelection *fileselect;
/* Eine Grafik in einen Pixbuf laden */
pic = gdk_pixbuf_new_from_file("icon/at-work.gif", NULL );
/* Fenster mit folgenden Eigenschaften anlegen */
window = g_object_new( GTK_TYPE_WINDOW,
"title", "Textansicht und Textpuffer",
"default-width", 300,
"default-height", 200,
"resizable", TRUE,
"window-position", GTK_WIN_POS_CENTER,
"border-width", 0,
"icon", pic,
NULL );
/* eine vertikale Box erzeugen */
vbox_main = g_object_new( GTK_TYPE_VBOX,
"spacing", 0,
NULL);
/* Eine neue Toolbar erzeugen */
toolbar = g_object_new (GTK_TYPE_TOOLBAR,
/* "toolbar-style", GTK_TOOLBAR_ICONS,*/
NULL);
/* Buttons mit Stock-Icons für die Toolbar erzeugen */
button_open = gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-open",
"Datei oeffnen",
NULL, NULL, NULL, -1);
button_save = gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-save",
"Datei speichern",
NULL, NULL, NULL, -1);
button_clear=gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-clear",
"Text loeschen",
NULL,NULL,NULL,-1);
button_cut=gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-cut",
"Text ausschneiden",
NULL, NULL, NULL, -1);
button_copy = gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-copy",
"Text kopieren",
NULL, NULL, NULL, -1);
button_paste=gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-paste",
"Text einfuegen",
NULL, NULL, NULL, -1);
gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
button_bold = gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-bold",
"Fette Schriftart",
NULL, NULL, NULL, -1);
button_underline=gtk_toolbar_insert_stock(
GTK_TOOLBAR (toolbar),
"gtk-underline",
"Schrift unterstreichen",
NULL, NULL, NULL, -1);
button_strike=gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-strikethrough",
"Schrift durchstreichen",
NULL, NULL, NULL, -1);
button_color=gtk_toolbar_insert_stock (GTK_TOOLBAR (toolbar),
"gtk-select-color",
"farbige Schrift (Blau)",
NULL, NULL, NULL, -1);
/* Rollbalken erzeugen */
scrolledwindow = g_object_new( GTK_TYPE_SCROLLED_WINDOW,
"hscrollbar_policy" , GTK_POLICY_AUTOMATIC,
"vscrollbar_policy" , GTK_POLICY_AUTOMATIC,
"window_placement" , GTK_CORNER_TOP_LEFT,
NULL);
/* Eine Textansicht erzeugen */
textview = g_object_new( GTK_TYPE_TEXT_VIEW, NULL);
/* Aktuellen Puffer für die Textansicht ermitteln */
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
/* Einige einfache Tags zur Formatierung anlegen */
create_tags (buffer);
/* Dateiauswahlbox erzeugen */
fileselect = g_object_new( GTK_TYPE_FILE_SELECTION,
"filename" ,"Bitte Datei auswaehlen ...",
"select-multiple", FALSE,
"show-fileops" , TRUE,
NULL);
/* Signalhandler einrichten */
g_signal_connect ( (gpointer) window, "delete_event",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect ( (gpointer) button_clear, "clicked",
G_CALLBACK (on_button_clear_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_cut, "clicked",
G_CALLBACK (on_button_cut_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_copy, "clicked",
G_CALLBACK (on_button_copy_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_paste, "clicked",
G_CALLBACK (on_button_paste_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_bold, "clicked",
G_CALLBACK (on_button_bold_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_underline, "clicked",
G_CALLBACK (on_button_underline_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_strike, "clicked",
G_CALLBACK (on_button_strike_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_color, "clicked",
G_CALLBACK (on_button_color_clicked),
(gpointer) textview);
g_signal_connect ( (gpointer) button_save, "clicked",
G_CALLBACK (on_button_save_clicked),
(gpointer) textview);
g_signal_connect (GTK_OBJECT
(GTK_FILE_SELECTION (fileselect)->ok_button),
"clicked", G_CALLBACK(ok_buttonCB), fileselect);
g_signal_connect_swapped (
GTK_OBJECT(GTK_FILE_SELECTION (fileselect)->ok_button),
"clicked",
G_CALLBACK(gtk_widget_hide),
GTK_OBJECT (fileselect));
g_signal_connect_swapped (
GTK_OBJECT(GTK_FILE_SELECTION (fileselect)->cancel_button),
"clicked",
G_CALLBACK(gtk_widget_hide),
GTK_OBJECT (fileselect));
g_signal_connect (GTK_OBJECT(button_open), "clicked",
G_CALLBACK (file_open), fileselect);
/* Alles packen */
gtk_container_add( GTK_CONTAINER (window),
GTK_WIDGET(vbox_main) );
gtk_box_pack_start ( GTK_BOX (vbox_main),
GTK_WIDGET(toolbar),
FALSE, FALSE,0);
gtk_box_pack_start ( GTK_BOX (vbox_main),
GTK_WIDGET(scrolledwindow),
TRUE,TRUE, 0);
gtk_container_add ( GTK_CONTAINER (scrolledwindow),
GTK_WIDGET(textview));
/* Erzeugtes Fenster zurückgegeben */
return window;
}
/* Bitte entnehmen Sie die Funktionen ...
* on_button_clear_clicked(), on_button_cut_clicked(),
* on_button_copy_clicked(), on_button_paste_clicked(),
* on_button_bold_clicked(), on_button_underline_clicked(),
* on_button_strike_clicked(), on_button_color_clicked (),
* create_tags ()
* ... vom Beispiel gtk7.c oder von der Buch-CD.
*/
/* Datei zum Lesen öffnen */
static void
ok_buttonCB (GtkWidget * clicked, GtkWidget * selection) {
FILE *f;
gchar buf[255];
GtkTextBuffer *buffer = NULL;
GtkTextIter end;
file=gtk_file_selection_get_filename (
GTK_FILE_SELECTION(selection));
if (file == NULL)
return; /* Datei existiert nicht */
f = fopen (file, "r");
if (NULL == f) {
printf("Keine solche Datei vorhanden!!\n");
return;
}
else {
buffer = gtk_text_view_get_buffer (
GTK_TEXT_VIEW (textview) );
while(fgets(buf,255,f)) {
gtk_text_buffer_get_end_iter(buffer, &end);
gtk_text_buffer_insert(buffer, &end, buf, -1);
}
}
fclose (f);
}
static void
file_open (GtkButton * clicked, GtkWidget * selection) {
GtkTextBuffer *buffer = NULL;
/* Neue Datei öffnen, daher:
+ Dateinamen auf NULL setzen
+ Inhalt von bereits vorhandenem Text löschen */
file = NULL;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
gtk_text_buffer_set_text(buffer,"", -1);
gtk_widget_show (selection);
}
/* Datei abspeichern - ohne wenn und aber !*/
static void
on_button_save_clicked (GtkButton * button, gpointer user_data) {
GtkTextBuffer *buffer = NULL;
GtkTextIter start, end;
gchar *buf;
gchar *dyn;
FILE *f;
if(file != NULL) {
/* Aktuellen Puffer für die Textansicht ermitteln */
buffer = gtk_text_view_get_buffer (
GTK_TEXT_VIEW (user_data) );
/* Markierte Auswahl im Puffer ermitteln */
gtk_text_buffer_get_bounds (buffer, &start, &end);
/* Zeiger auf den kompletten Text zurück */
buf=gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
dyn = g_malloc( strlen(buf)+1 );
g_stpcpy( dyn, buf );
/* Zur Kontrolle Ausgabe auf die Konsole */
g_print("%s\n... gespeichert!\n",dyn);
f = fopen(file, "w");
if(f != NULL)
fwrite(dyn, strlen(dyn)+1, 1, f);
fclose(f);
}
}
int main (int argc, char **argv) {
GtkWindow *window;
gtk_init (&argc, &argv);
window = create_window ();
gtk_widget_show_all (GTK_WIDGET(window));
gtk_main ();
return 0;
}
Das Programm bei der Ausführung:
$ gcc -Wall -o gtk8 gtk8.c `pkg-config gtk+-2.0 --cflags --libs`
$ ./gtk8
Hinweis Aus drucktechnischen Gründen wurde auch hier wieder die Toolbar des Listings auf dem Screenshot mit der Eigenschaft "toolbar-style", GTK_TOOLBAR_ICONS versehen; also ohne den Text unter dem Icon.
|
Hinweis Bei diesem Beispiel wurden Sie höchstwahrscheinlich zum ersten Mal mit UTF-8-Warnmeldungen in der Konsole überschüttet, aus der Sie das Programm gestartet haben. Natürlich nur, wenn die Datei, die Sie öffnen, Nicht-ASCII-Zeichen enthält. Zwangsläufig müssen Sie sich hierbei wohl intensiver mit den UTF-8-Funktionen der Glib auseinander setzen, wenn Sie derartige Programme für die Masse entwickeln wollen.
|
15.12.1 Dateiauswahl – GtkFileSelection
Wie Sie im Beispiel schon gesehen haben, ist es üblich, diesen Dialog via Signalhandler anzulegen – genauer, anzeigen zu lassen, indem die Buttons OK und Abbrechen mit dieser Dialogbox gebunden und ausgewertet werden. Beide Buttons finden Sie in der Struktur GtkFileSelection unter dem Namen ok_button und cancel_button.
struct GtkFileSelection {
...
GtkWidget *ok_button;
GtkWidget *help_button;
...
};
Folgende Eigenschaften stehen Ihnen bei der Dateiauswahl zur Verfügung:
Tabelle 15.28
Eigenschaften für GtkFileSelection
Eigenschaft
|
Datentyp
|
Bedeutung
|
"filename"
|
gchararray
|
Der Dateiname mit Pfad, der ausgewählt wurde. Macht allerdings nur Sinn auszuwerten, wenn select-multiple FALSE ist.
|
"select-multiple"
|
gboolean
|
Bei TRUE können mehrere Dateien auf einmal ausgewählt werden (bei gedrückter (STRG)-Taste möglich).
|
"show- fileops"
|
gboolean
|
Sollen die Buttons zur Dateiverwaltung mit angezeigt werden (Verzeichnis anlegen, Datei löschen, Datei umbenennen)?
|
Wie schon erwähnt, können Sie auch mehrere Dateien auf einmal selektieren. Dann allerdings müssen Sie die Funktion gtk_file_selection_get_selections() verwenden. Mit dieser Funktion erhalten Sie ein nullterminiertes Feld von Strings zurück, worin die Dateinamen enthalten sind. Allerdings sind in den Dateinamen die lokalen Zeichenkodierungen enthalten. Damit es nicht reihenweise Fehler oder gar Abstürze hagelt, sollten Sie die Dateinamen zuvor in eine UTF-8-Kodierung mit der Funktion g_filename_from_utf8() umwandeln. Dies natürlich nur, wenn Nicht-ASCII-Zeichen beim Dateinamen verwendet wurden. Das UTF-8-Problem wurde bereits zu Beginn kurz angesprochen.
Im Beispiel wurde die Funktion gtk_file_selection_get_filename() mit der Dateiauswahl GtkFileSelection als Argument verwendet, um den Dateinamen mitsamt Pfad zu ermitteln, der ausgewählt wurde.
Ferner wurden noch weitere Funktionen verwendet, die sich auf GtkTextBuffer beziehen, die hier nicht unerwähnt bleiben sollten.
void gtk_text_buffer_get_end_iter ( GtkTextBuffer *buffer,
GtkTextIter *iter );
void gtk_text_buffer_insert ( GtkTextBuffer *buffer,
GtkTextIter *iter,
const gchar *text,
gint len );
void gtk_text_buffer_get_bounds ( GtkTextBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end );
gchar *gtk_text_buffer_get_text( GtkTextBuffer *buffer,
const GtkTextIter *start,
const GtkTextIter *end,
gboolean include_hidden_chars );
Mit gtk_text_buffer_get_end_iter() ermitteln Sie das Ende des Textpuffers. Die so ermittelte Adresse verwenden Sie anschließend in der Funktion gtk_text_buffer_insert(). Mit dieser Funktion wird ein Text text an der Position iter mit der Länge len angefügt. Für len kann auch –1 angegeben werden, was allerdings voraussetzt, dass der Text nullterminiert ist.
Mit der Funktion gtk_text_buffer_get_bounds() ermitteln Sie die Startposition (start) und Endposition (end) im Textpuffer (buffer). Diese beiden so ermittelten Iteratoren werden gleich mit der Funktion gtk_text_buffer_get_text() verwendet, die aus dem Textpuffer dann eine Adresse auf den kompletten Text zwischen diesen beiden Iteratoren zurückgibt. Mit include_hidden_chars können Sie angeben, ob auch unsichtbare Zeichen mitgenommen werden.
|