Manuel Kiessling's Personal Home Page
Navigate:      Previous | Next Home | Sitemap | News | Personal | Projects | Topics | Download | External Links | About this page

PHP-Gtk Tutorial

Walkthrough des Listings, Teil 1



<?php

// Startup //////////////////////////////////////////////////////

if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
 dl('php_gtk.dll');
else
 dl('php_gtk.so');

Hier wird lediglich überprüft, auf welcher Plattform wir uns befinden, und dementsprechend wird die passende Bibliothek geladen. Unter Windows muss die Bibliothek offensichtlich im selben Verzeichnis wie das Skript liegen, unter Linux erwartet PHP die Bibliotheken (php_gtk.so und php_gtk.la) im Verzeichnis /usr/local/lib/php/extensions/no-debug-non-zts-20001222 obwohl ich --prefix=/usr/local bei der Installation von PHP-Gtk angegeben hatte. Egal, nachdem ich die Dateien dorthin kopiert hatte, liefs.

// Init //////////////////////////////////////////////////////

mysql_connect("localhost", "root", "passwort");
mysql_select_db("test");

$verschiebung = 0;



// Support functions //////////////////////////////////////////////////////

function sonderzeichen($string)
{
 $string = str_replace("ä", "ae", $string);
 $string = str_replace("ü", "ue", $string);
 $string = str_replace("ö", "oe", $string);
 $string = str_replace("Ä", "Ae", $string);
 $string = str_replace("Ü", "Ue", $string);
 $string = str_replace("Ö", "Oe", $string);
 $string = str_replace("ß", "ss", $string);
 $string = str_replace("", "", $string);
 return $string;
}

Bis hierher noch keinerlei Gtk. Die MySQL Verbindung ist klar, die Sonderzeichenfunktion brauchen wir, weil PHP-Gtk etwas seltsam auf deutsche Umlaute reagiert, nämlich gar nicht. Das Programm startet zwar, aber Elemente, die Umlaute enthalten, werden nicht angezeigt, oder genauer: ein Button mit dem Text "Drück mich" wird zwar als Button angezeigt, jedoch völlig ohne den Text. Hoffen wir dass dies ein Bug ist, kein Feature.

// GUI init //////////////////////////////////////////////////////

$window = &new GtkWindow();
$window->connect_object('destroy', array('gtk', 'main_quit'));
$window->set_usize(800, 600);
$window->set_title('GPMNA');
$window->set_name('MainWindow');

Zuallererst einmal wird das Fenster erschaffen. Da das Gtk Toolkit komplett objektorientiert ist, wird jedes Element auch als PHP Objekt angelegt. Als nächstes wird dieses Fensterobjekt mit einem Event verbunden. Dieses verbinden von Events mit Funktionen ist eine zentrale Grundlage des Gtk Toolkits. Man kann sich das ähnlich wie bei JavaScript vorstellen.
Wenn ich einen Link folgendermassen deklariere:

<a href="#" OnClick="irgendeinefunktion();">Blubb</a>
dann habe ich den Event OnClick (also Mausklick) mit der Funktion irgendeinefunktion() verbunden. Genau dies tut $window->connect_object. In diesem Falle verbinde ich den Event destroy (Schliessen des Fensters) mit array('gtk', 'main_quit'). Normalerweise verbindet man diese Events mit selbstgeschriebenen Funktionen. In diesem Fall löst der Aufruf der Array-Funktion wohl eine interne Gtk Funktion auf, die für das Schliessen des Fensters und das Beenden des Skripts sorgt.
Jetzt setzen wir noch ein paar Eigenschaften unseres Fensters. Die Funktion set_usize() legt die horizontale und vertikale Grösse des Fensters fest, set_title die im Fensterkopf angezeigte Überschrift und set_name den internen Namen.

$box1 = &new GtkVBox(false, 0);
$window->add($box1);

Eine weitere Grundlage des Gtk ist die Verschachtelung von Elementen, denn in dem bis jetzt angelegten Fenster könnten wir nur ein Element (z.B. einen Button anlegen). Um in unserem Fenster weitere Elemente einbauen zu können, brauchen wir erstmal eine Box. Eine Box ist ein unsichtbarer Container, in den wir weitere Elemente "packen" können, und zwar gibt es horizontale und vertikale Boxen, in denen Elemente (natürlich auch weitere Boxen) entweder von links nach rechts (bzw. oben nach unten) oder aber von rechts nach links (bzw. unten nach oben) angeordnet werden können.
Die Parameter false und 0 in unserem Beispiel geben an, das Unterelemente der Box nicht homogen angeordnet werden und einen Abstand von 0 Pixeln zueinander haben. Da unsere Box nur ein Unterelement haben wird, sind diese Werte hier sowieso unerheblich. Dann müssen wir noch dafür sorgen, dass die Box ein Unterelement unseres Fensters ist, sonst würde sie nämlich im Nirgendwo "befestigt" sein. Das erledigt der Befehl add. Erstellen wir nun das eben erwähnte Unterelement:

$table = &new GtkTable(4, 2, false);
$table->set_row_spacing(0,2);
$table->set_col_spacing(0,2);
$box1->pack_start($table, TRUE, TRUE, 0);

Wir erstellen eine Table. Dies ist wie die Box ein für sich genommen unsichtbares Containerelement, dass es (genau wie Tabellen in HTML) erlaubt, weitere Unterelemente an einem definierten Raster auszurichten. Bei der Erzeugung unserer Tabelle geben wir an, dass sie 4 Spalten und 2 Reihen erhalten soll und dass die Zellen nicht homogen gehalten werden sollen. Homogen bedeutet in diesem Falle, dass automatisch alle Zellen genau so gross sind wie die Zelle mit dem grössten Inhalt. Dann legen wir das Spacing, also den Abstand der Tabellenzellen zueinander, fest, und zwar zuerst für die Reihe 0 den Abstand 2, dann für die Spalte 0 den Abstand 2. Das macht in unserem Falle aber gerade für die Zeile wenig Sinn und soll nur die Anwendungsweise zeigen. Damit auch die Tabelle nicht im Nirgendwo hängt, packen wir sie in die zuvor erzeugte Box. Die Funktion pack_start packt ein Element an den Anfang einer Box, pack_end würde ans Ende anfügen. Dies spielt natürlich nur dann eine Rolle wenn schon Elemente in einer Box vorhanden sind.
Also, kurze Zwischenbilanz: Wir haben ein Fenster erstellt, dorthinein haben wir eine Box platziert, und in diese wiederum haben wir eine Tabelle mit 4 Zeilen und 2 Reihen gepackt. Jetzt werden wir endlich Elemente erstellen, die man auch sieht, und werden diese an der Tabelle ausrichten.

$text = &new GtkText(NULL, NULL);
$text->set_editable(FALSE);
$text->set_word_wrap(TRUE);
$table->attach($text, 0, 1, 0, 1,
               GTK_EXPAND | GTK_SHRINK | GTK_FILL,
               GTK_EXPAND | GTK_SHRINK | GTK_FILL,
               0, 0);

Wir erzeugen zunächst einmal ein Textfeld, in dem wir den Inhalt der ausgeählten Nachricht anzeigen können. Die beiden Parameter, die wir beim Erzeugen angeben, sind die horizontale und vertikale Ausrichtung der Box. Wir setzen beides auf NULL und lassen das Textfeld somit selbst über seine Ausrichtung entscheiden - in unserem Design spielt das sowieso keine Rolle. Da wir das Textfeld nur zum Anzeigen und nicht zum Bearbeiten von Text verwenden wollen, setzten wir die Eigenschaft editable auf FALSE. Damit Wörter sauber umgebrochen werden und nicht mitten in einem Wort umgebrochen wird, setzen wir das Wordwrapping des Textfeldes auf TRUE. Jetzt kommt des wichtigste: Wir teilen dem Textfeld mit, wo in der Tabelle es platziert werden soll. Da wir es in der obersten linken Ecke platzieren wollen, geben wir dem attach Befehl unserer Tabelle nach Angabe des zu platzierenden Objekts die gewünschen Koordinaten mit, in diesem Falle 0, 1, 0, 1, was bedeutet "Objekt $text soll sich von Spalte 0 bis 1 und von Zeile 0 bis 1 erstrecken", es füllt somit also genau eine Tabellenzelle aus. Die weiteren Parameter GTK_EXPAND, GTK_SHRINK und GTK_FILL geben an, ob und wie das hinzugefügte Objekt mit wächst und schrumpft, wenn die Tabellengrösse geändert wird. Ich muss gestehen dass ich hier noch nicht durch die Logik durchblicke - jedenfalls klappt es so :-). Die beiden letzten Parameter geben das Padding, also den horizontalen bzw. vertikalen Abstand des Objekts zu umgebenden Objekten an. Die Ähnlichkeit mit HTML Tabellen dürfte die Funktionsweise klarmachen.

$vscrollbar = &new GtkVScrollbar($text->vadj);
$table->attach($vscrollbar, 1, 2, 0, 1,
               GTK_FILL,
               GTK_EXPAND | GTK_SHRINK | GTK_FILL,
               0, 0);

Da unser Textfeld von Haus aus keine Scrolleiste (für den Fall dass mehr Inhalt als sichtbare Zeilen in das Textfeld geladen wird) mitbringt, müssen wir noch ein Objekt vom Typ GtkVScrollbar erzeugen. Schon beim Erstellen des Objekts übergeben wir den vadj Parameter des Textfeldes, damit die Scrollleiste mit dem Textfeld korrekt verbunden wird. Dann wird die fertige Scrollleiste nur noch wie zuvor das Textfeld an eine sinnvolle Position rechts neben dem Textfeld platziert, sie soll sich also von Spalte 1 bis 2 und (genau wie das Textfeld) von Zeile 0 bis 1 erstrecken. Obwohl das ja die klassische Position einer Scrolleiste ist, ist sie keinesfalls vorgeschrieben. Die Leiste könnte sich an völlig anderer Position optisch losgelöst vom Textfeld befinden, und trotzdem könnte man das Textfeld weiterhin scrollen - wahrscheinlich würde sich die Bedienung dann aber sehr seltsam "anfühlen". Nun zur Buttonleiste:

$table2 = &new GtkTable(1, 6, false);
$table->attach($table2, 0, 1, 1, 2, 0, 0, 0);

Genau, erstmal erstellen wir wieder eine Tabelle, um die Buttons sauber nebeneinander platzieren zu können. Das lässt sich wahrscheinlich etwas einfacher auch mit einer horizontalen GtkBox realisieren, aber ehrlichgesagt ist mir das erst jetzt eingefallen, und diese Vorgehensweise zeigt die Verschachtelung einer Tabelle in einer anderen, also warum nicht (ausserdem: wenn ich mir die Arbeit schon gemacht habe, werde ich sie euch nicht vorenthalten :-). Jedenfalls genau die selbe Vorgehensweise wie beim Erstellen der ersten Tabelle: Objekt erschaffen (auf Spacing verzichten wir hier) und an gewünschter Position der ersten Tabelle einfügen, und zwar von Spalte 0 bis Spalte 1 und Zeile 1 bis Zeile 2.
Jetzt können wir die Buttons in die zweite Tabelle einfügen.

$beenden = &new GtkButton('Beenden');
$beenden->connect_object('clicked', array('gtk', 'main_quit'));
$table2->attach($beenden, 0, 1, 0, 1, 0, 0, 0);

Ich erkläre hier nur den ersten Button, die anderen werden genauso eingebaut. Erstmal wird das GtkButton wieder erschaffen, dann mit einer Funktion verbunden (hier wieder dieses seltsame Array welches das Programm beendet), und zwar über den Event clicked (= Button wurde gedrückt), und schliesslich an geeigneter Stelle in der zweiten Tabelle positioniert (Von Zeile 0 bis 1 und Spalte 0 bis 1).
Die anderen Buttons werden jetzt nach dem selben Muster hinzugefügt und jeweils eine Spalte rechts vom Vorgänger platziert:

$prevday = &new GtkButton('Einen Tag zurueck');
$prevday->connect_object('clicked', 'lade_prevday');
$table2->attach($prevday, 1, 2, 0, 1, 0, 0, 0, 0);

$nextday = &new GtkButton('Einen Tag vor');
$nextday->connect_object('clicked', 'lade_nextday');
$table2->attach($nextday, 2, 3, 0, 1, 0, 0, 0, 0);

$prevweek = &new GtkButton('Eine Woche zurueck');
$prevweek->connect_object('clicked', 'lade_prevweek');
$table2->attach($prevweek, 3, 4, 0, 1, 0, 0, 0, 0);

$nextweek = &new GtkButton('Eine Woche vor');
$nextweek->connect_object('clicked', 'lade_nextweek');
$table2->attach($nextweek, 4, 5, 0, 1, 0, 0, 0, 0);

$delete = &new GtkButton('Loeschen');
$delete->connect_object('clicked', 'loesche_eintrag');
$table2->attach($delete, 5, 6, 0, 1, 0, 0, 0, 0);

Die Funktionen, mit denen die einzelnen Buttons hier connected werden, werden wir weiter unten schreiben.
Jetzt fügen wir noch ein Label (das ist ein Darstellungsfeld für wenig Textinhalt) unterhalb der Tabelle, die die Buttons beinhaltet, ein, um dort später einige Informationen über die aktuell ausgewählte Nachricht anzeigen zu können:

$label = &new GtkLabel('');
$label->set_text("Bereit.");
$table->attach($label, 0, 1, 2, 3, 0, 0, 0);

Nach dem Erzeugen des Objekts weisen wir dem Label noch einen ersten Textinhalt mit der Funktion set_text zu, dann fügen wir es in die dritte Reihe der Tabelle ein - jetzt wieder die erste Tabelle, die zweite war nur für die Anordnung der Buttons gedacht.
Kommen wir jetzt zu der Liste, die die verschiedenen Newsbeiträge anzeigen wird. Das Objekt GtkCList ist schon etwas komplexer, wir gehen die Erzeugung deshalb Schritt für Schritt durch:

$listtitles = array("ID", "Ueberschrift", "Rubrik");

Eine GtkCList ist ja eigentlich eine Tabelle. Wir legen diese dreispaltig an, und um die Spalten benennen zu können, muss zunächst ein Array mit den drei Spaltennamen angelegt werden.

$list = &new GtkCList(3, $listtitles);

Jetzt erzeugen wir die Liste, geben an dass sie 3 Spalten haben soll, und übergeben das soeben erzeugte Array, aus dem dann die Spaltentitel erzeugt werden.

$list->set_selection_mode(GTK_SELECTION_BROWSE);

Hier legen wir den Auswahlmodus (selection_mode) der Liste fest. Es gibt 4 Modi: GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE und GTK_SELECTION_EXTENDED. Bei den ersten beiden Modi kann immer nur eine Zeile der Liste gleichzeitig gewählt sein, wobei bei GTK_SELECTION_SINGLE nur ein "vollständiger" Mausklick auf eine Zeile diese auch auswählt, während man bei GTK_SELECTION_BROWSE mit gedrückter Maustaste durch die Liste "surfen" kann und immer die Zeile ausgewählt wird, in der sich der Mauszeiger gerade befindet. Bei den beiden anderen Modi kann mehr als ein Element auf einmal angewählten werden, wobei man bei GTK_SELECTION_EXTENDED mehrere Elemente mit der weit verbreiteten Methode auswählt, nämlich in dem man mittels Shift-Taste ganze Bereiche und mittels Strg-Taste einzelne Einträge der Auswahl hinzufügt. Bei der Verwendung von GTK_SELECTION_MULTIPLE dagegen fügt schon ein einfacher Klick auf ein Element dieses der Auswahl hinzu, ein Klick auf ein schon ausgewähltes Element entfernt es wieder - eher nervig als sinnvoll.
Wir entscheiden uns hier für GTK_SELECTION_BROWSE, da diese Methode die schnellste und angenehmste darstellt, um die Liste zu durchforsten.

$list->set_sort_column(0);
$list->set_auto_sort(TRUE);

Nun sorgen wir noch dafür, dass wir immer eine sauber sortierte Liste haben. Mit dem Befehl set_sort_column legen wir fest, dass die Spalte, an der sich die Sortierung orientieren soll, die erste (also Spalte 0) sein soll, das ist die mit den IDs, und weiterhin legen wir fest, dass die Liste jedesmal, wenn ein Element hinzugefügt wird, automatisch nachsortiert werden soll.

$list->set_column_width(0, 55);
$list->set_column_width(1, 570);

Hier passen wir die Breite der einzelnen Spalten sinnvoll an. Der erste Parameter von set_column_width gibt die zu verändernde Spalte an, der zweite Parameter den Wert der gewünschten Breite in Pixeln. Die dritte Spalte muss hier nicht angepasst werden, denn deren Wert ergibt sich nach Festlegung der beiden anderen von selbst.

$list->connect_object('select-row', 'list_change');

Schlussendlich verbinden wir den Event select-row (Eine Zeile wird ausgewählt) mit der Funktion list_change (die wir gleich definieren werden, versprochen).
Jetzt ist die Liste eigentlich fertig, aber auch das GtkCList Objekt bringt von Haus aus leider keine Scrollleiste mit. Deshalb müssen wir (anders als bei der Textbox!) unser Listenobjekt in ein GtkScrolledWindow einfügen. Der Begriff Window ist etwas verwirrend, es handelt sich hier nicht um ein regelrechtes Programmfenster wie wir es zu Beginn erstellt haben, sondern um ein unsichtbares Feld mit einer Scrolleiste. Wenn die Elemente, die man diesem Feld hinzufügt, grösser als das Feld selbst sind, kann man die Scrolleiste benutzen, um, naja, halt zu scrollen.
Wir erstellen also das GtkScrolledWindow:

$scrolled_window = &new GtkScrolledWindow();
$scrolled_window->set_policy(GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
$scrolled_window->add_with_viewport($list);

Über die Funktion set_policy legen wir fest, dass die horizontale bzw. vertikale Scrolleiste bei Bedarf automatisch erscheint. Es gibt noch GTK_POLICY_ALWAYS und GTK_POLICY_NEVER - die Namen sprechen für sich.
Im letzten Schritt fügen wir unsere Liste dem GtkScrolledWindow via add_with_viewport hinzu.
Jetzt muss noch dieses Window mit der enthaltenen Liste in unsere Tabelle eingefügt werden:

$table->attach($scrolled_window, 0, 1, 3, 4,
               GTK_EXPAND | GTK_SHRINK | GTK_FILL,
               GTK_EXPAND | GTK_SHRINK | GTK_FILL,
               0, 0);

So, an dieser Stelle steht unser Gtk Gerüst eigentlich. Jetzt müssen wir noch definieren dass alle Elemente in unserem Programmfenster auch angezeigt werden:

$window->show_all();

...und die Main Routine der Gtk Bibliothek starten:

Gtk::main();
?>

Und schon haben wir eine lauffähige PHP-Gtk Anwendung. Die einzelnen Funktionen, die aufgerufen werden, wenn z.B. ein Button gedrückt wird, sind zwar noch nicht vorhanden, trotzdem kann man das Skript schon mittels

# /usr/local/bin/php -q /pfad/zum/gpnma-skript.php

starten. Wenn man einen Event auslöst, z.B. durch drücken eines Buttons, wird PHP lediglich an der Konsole einen Fehler ausgeben.

Im zweiten Teil des Walthroughs werden wir nun die Funktionen definieren, die die einzelnen Events der Gtk-Elemente abfangen.


Top of page | Previous | Next
There is a lightwheight and printerfriendly version of this page.
Last updated: $Date: 2001/07/15 17:56:09 MEST $

Everything on this page is copyleft 2001 Manuel Kiessling unless otherwise stated. You may use it after you read the About section. For any questions or suggestions send an eMail.

Valid HTML 4.0 | Viewable with Any Browser | Bobby approved
Wenn Sie sich für Car-HiFi, Navigationssysteme oder Freisprecheinrichtungen interessieren, dann besuchen Sie die Homepage meines Vaters.
This page was generated with QuickHP.