Aus Raspberry Pi Geek 06/2017

GTK+: Schicke GUI für RasPi-Programme (Seite 2)

Die folgenden Funktionen tragen sprechende Namen, die ihre Funktion verdeutlichen: Sie setzen Titel, Größe und Position des Fensters (Zeile 8 bis 10). Die Funktion gtk_widget_show() macht das resultierende Fenster sichtbar (Zeile 11), gtk_main() steuert die komplette Anwendung (Zeile 12). Dabei handelt es sich quasi um eine Endlosschleife, die auf das Auftreten bestimmter Ereignisse wartet.

Listing 2

 

/* HalloWelt.c */
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
  gtk_init(&argc, &argv);
  GtkWidget *w;
  w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(w), "Hallo Welt");
  gtk_window_set_default_size(GTK_WINDOW(w), 200, 200);
  gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER);
  gtk_widget_show(w);
  gtk_main();
  return 0;
}

Listing 3 zeigt, wie Sie das Programm kompilieren und starten. Die dabei erscheinenden Warnungen spielen für unser Beispiel keine Rolle, Sie dürfen sie getrost ignorieren. Nach dem Start des Programms erscheint in der Mitte des Bildschirms das Fenster aus Abbildung 1.

Listing 3

 

$ gcc HalloWelt.c -o HalloWelt $(pkg-config --cflags gtk+-3.0 --libs)
$ ./HalloWelt
** (HalloWelt:27409): WARNING **: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-j2RFteUeAs: Connection refused
Gtk-Message: Failed to load module "canberra-gtk-module"
Gtk-Message: Failed to load module "canberra-gtk-module"
Abbildung 1: Die Ausgabe unseres Hallo-Welt-Programms.

Abbildung 1: Die Ausgabe unseres Hallo-Welt-Programms.

Klick mich!

Bis hierher bleibt unser Programmfenster bedauerlich leer und erlaubt keinerlei Interaktion. Höchste Zeit also, sich einem der zentralen Steuerelemente jedes Programms zuzuwenden, der Schaltfläche oder neudeutsch dem Button. Um einen solchen zu verwenden, benötigen Sie in der GTK+-Programmierung dreierlei:

  • den Button selbst. Dabei handelt es sich um ein GTK+-Widget, das Sie ähnlich wie ein GTK-Fenster über eine entsprechende Funktion (gtk_button_new_with_label()) erstellen.
  • eine Funktion, die das Programm ausführt, sobald Sie den Button anklicken. Im Beispiel aus Listing 4 heißt diese schlicht klick(); und beendet das GTK+-Programm (Zeile 4 bis 6).
  • eine Verbindung zwischen Button und der Ereignisauswertung. Die richtet die Funktion g_signal_connect() für Sie ein (Zeile 18).

Listing 4

 

/* Button.c */
#include <gtk/gtk.h>
void klick(GtkWidget *widget, gpointer data) {
  gtk_main_quit();
}
int main(int argc, char *argv[]) {
  GtkWidget *w;//window
  GtkWidget *b;//button
  gtk_init(&argc, &argv);
  w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(w), "Button");
  gtk_window_set_default_size(GTK_WINDOW(w), 200, 200);
  gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER);
  gtk_container_set_border_width(GTK_CONTAINER(w),25);
  b = gtk_button_new_with_label("Button");
  g_signal_connect(b, "clicked", G_CALLBACK(klick), NULL);
  gtk_container_add(GTK_CONTAINER(w), b);
  gtk_widget_show_all(w);
  gtk_main();
  return 0;
}

Mit diesen wenigen Mitteln lässt sich bereits ein einfacher Button realisieren, wie Sie ihn in Abbildung 2 sehen. Im Beispiel aus Listing 4 haben wir ihn der Einfachheit halber so definiert, dass er stets den kompletten zur Verfügung stehenden Platz verwendet. Daher sieht er in Abbildung 2 etwas unförmig aus. Um ihn in einem gefälligeren Format darzustellen, müssten Sie ihn in ein GTK+-Widget einbinden, das seinen Platz beschränkt. Sie könnten ihn beispielsweise in eine Box fester Größe einbinden.

Abbildung 2: Die Ausgabe unseres Button-Testprogramms.

Abbildung 2: Die Ausgabe unseres Button-Testprogramms.

Gegenüber dem Hallo-Welt-Beispiel weist das Button-Programm eine wichtige neue Funktion namens gtk_widget_show_all() auf (Zeile 18). Sie macht alle Widgets sichtbar und nicht nur ein einzelnes wie gtk_widget_show(). Ob Sie alle Widgets auf einmal sichtbar machen oder lieber jedes einzeln, hängt stark von der Funktionsweise der Anwendung ab.

Dieses Testprogramm kompilieren und starten Sie genau wie HalloWelt.c, allerdings heißt die Quellcode-Datei diesmal Button.c. Das resultierende Binärprogramm Button glänzt zwar mit einem Schalter, über den es sich beenden lässt, aber das war es dann auch schon.

Eins, zwei, viele

Unser nächstes Testprogramm aus Listing 5 implementiert einen einfachen Zähler für den Bereich von 1 bis 100. Damit keine Langeweile aufkommt, zeigt die Software den Zählerstand grafisch über eine sogenannte Level Bar an (Abbildung 3).

Abbildung 3: Das Testprogramm verfügt nun über einen Zähler.

Abbildung 3: Das Testprogramm verfügt nun über einen Zähler.

An diesem Programm kann man gut sehen, dass alle GTK+-Widgets immer nach der gleichen Methodik aufgebaut sind. Als kniffelig erweist es sich hierbei, das Layout optisch ansprechend hinzubekommen: Es erfordert etwas Herumprobieren, die einzelnen Komponenten optimal anzuordnen.

Gegenüber der vorigen Version kommt in diesem Programm im Wesentlichen nur das Box-Widget hinzu (Zeile 46), mit dessen Hilfe sich die anderen Widgets horizontal oder vertikal anordnen lassen. Auf diese Weise entstehen mit etwas Geschick auch komplexe GUIs, da man die Boxen beliebig verschachteln darf.

Listing 5

 

/* Counter.c */
#include <gtk/gtk.h>
int zahl=50;
GtkWidget *anzeige,*level;
void inc(GtkWidget *widget, gpointer data) {
  zahl = zahl+1;
  gchar buf[3];
  sprintf(buf, "%i", zahl);
  gtk_label_set_text(GTK_LABEL(anzeige), buf);
  gtk_level_bar_set_value(GTK_LEVEL_BAR(level), zahl);
}
void dec(GtkWidget *widget, gpointer data) {
  zahl = zahl-1;
  gchar buf[3];
  sprintf(buf, "%i", zahl);
  gtk_label_set_text(GTK_LABEL(anzeige), buf);
  gtk_level_bar_set_value(GTK_LEVEL_BAR(level), zahl);
}
void ende(GtkWidget *widget, gpointer data) {
  gtk_main_quit();
}
int main(int argc, char *argv[]) {
  GtkWidget *fenster;
  GtkWidget *buttonInc;
  GtkWidget *buttonDec;
  GtkWidget *buttonExit;
  GtkWidget *hbox,*vbox,*label;
  gtk_init(&argc, &argv);
  fenster = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(fenster), "IncDec");
  gtk_window_set_default_size(GTK_WINDOW(fenster), 200, 200);
  gtk_window_set_position(GTK_WINDOW(fenster),GTK_WIN_POS_CENTER);
  gtk_container_set_border_width(GTK_CONTAINER(fenster),25);
  buttonDec = gtk_button_new_with_label("--");
  buttonInc = gtk_button_new_with_label("++");
  buttonExit = gtk_button_new_with_label("Exit");
  g_signal_connect(buttonDec, "clicked", G_CALLBACK(dec), NULL);
  g_signal_connect(buttonInc, "clicked", G_CALLBACK(inc), NULL);
  g_signal_connect(buttonExit, "clicked", G_CALLBACK(ende), NULL);
  vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
  label = gtk_label_new("GTKtest");
  gtk_container_add(GTK_CONTAINER(vbox), label);
  anzeige = gtk_label_new("50");
  gtk_container_add(GTK_CONTAINER(vbox),anzeige);
  level = gtk_level_bar_new();
  gtk_level_bar_set_min_value(GTK_LEVEL_BAR(level), 0);
  gtk_level_bar_set_max_value(GTK_LEVEL_BAR(level), 100);
  gtk_level_bar_set_value(GTK_LEVEL_BAR(level), 50);
  gtk_container_add(GTK_CONTAINER(vbox), level);
  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
  gtk_container_add(GTK_CONTAINER(hbox), buttonDec);
  gtk_container_add(GTK_CONTAINER(hbox), buttonInc);
  gtk_container_add(GTK_CONTAINER(hbox), buttonExit);
  gtk_container_add(GTK_CONTAINER(vbox), hbox);
  gtk_container_add(GTK_CONTAINER(fenster), vbox);
  gtk_widget_show_all(fenster);
  gtk_main();
  return 0;
}

Fazit

Wenn Sie auf dem Raspberry Pi hardwarenahe Programme schreiben möchten, kommen Sie über kurz oder lang nicht um C herum. GTK+ bietet dabei eine gute Möglichkeit, den Programmen eine schöne Benutzeroberfläche zu geben. Wenn Sie einen Blick in die Dokumentation der GTK+-Widgets [3] werfen, stellen Sie schnell fest, dass sich hier alle Komponenten finden, die Sie auch von anderen Programmen her kennen. Dabei macht das Toolkit seinem Namen alle Ehre und erlaubt einen schnellen Einstieg ohne steile Lernkurve. 

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben