%% LyX 1.5.4 created this file. For more info, see http://www.lyx.org/. %% Do not edit unless you really know what you are doing. \documentclass[twocolumn,ngerman]{article} \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} \setlength{\parskip}{\medskipamount} \setlength{\parindent}{0pt} \usepackage{url} \usepackage{graphicx} \makeatletter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. \newenvironment{lyxcode} {\begin{list}{}{ \setlength{\rightmargin}{\leftmargin} \setlength{\listparindent}{0pt}% needed for AMS classes \raggedright \setlength{\itemsep}{0pt} \setlength{\parsep}{0pt} \normalfont\ttfamily}% \item[]} {\end{list}} \usepackage{babel} \makeatother \begin{document} \title{GTK\texttt{+} mit Forth (1) - GTK Stock Viewer} \ifx\shorttitle\undefined\else \shorttitle{GTK Stock Viewer} \fi \author{Manfred Mahlow} % \begin{figure*}[b] \begin{center} \includegraphics[scale=0.78]{2008-03/Viewer} \caption{\label{fig:Viewer} GTK Stock Viewer unter Ubuntu 6.06} \end{center} \end{figure*} \maketitle In der VD 02/2008 hatte ich eine GTK\texttt{+}-API für (csp)Forth vorgestellt. Hier folgt nun ein erstes Anwendungsbeispiel mit einem gewissen praktischen Nutzen, ein Viewer für den GTK Stock\emph{.} \begin{multicols}{2} \section*{Der GTK Stock} Der GTK Stock ist eine Sammlung von vordefinierten graphischen Objekten, \emph{GTK Stock Items} genannt. Die Stock Items sind Kombinationen von Minibildern (Icons), Beschriftungen, Abkürzungsbuchstaben und Tastenkombinationen, die bevorzugt für Menüeinträge, Dialoge und Knöpfe verwendet werden sollen, um GTK\texttt{+}-Benutzerschnittstellen ein einheitliches Aussehen zu geben. Auf die Stock Items kann man über eindeutige Bezeichner, die \emph{Stock Ids}, zugreifen. Will man ein bestimmtes GTK Stock Item verwenden, muß man seinen Bezeichner kennen. Um dazu nicht immer wieder die GTK\texttt{+}-Dokumentation wälzen zu müssen, bietet es sich an, ein kleines Tool zu schreiben, mit dem man den Gtk Stock durchstöbern kann. \section*{Ein GTK Stock Viewer} In einer der GTK\texttt{+}-Bibliotheken, der \emph{libgtk}, gibt es eine Funktion \emph{gtk\_stock\_list\_ids}, die einen Zeiger auf eine Liste aller verfügbaren GTK Stock Items zurückgibt. Man könnte diese Liste einer \emph{GtkComboBox} zuweisen. Mit dieser könnte man die Liste anzeigen und ein Listenelement auswählen, das dann als \emph{GtkImage} und als \emph{GtkButton} angezeigt werden könnte. Das Ergebnis dieser Überlegungen ist der GTK Stock Viewer in Abbildung \ref{fig:Viewer}. \section*{Der Code} Der cspForth-Code, der den Viewer auf den Bildschirm zaubert, ist im Listing 1 zu sehen. Der Code in den Zeilen 3 bis 9 stellt sicher, dass alle benötigten GTK\texttt{+}-Widget-Klassen geladen werden (einmaliges Laden der Quelltextmodule). Außerdem wird die Klasse \emph{GSList} benötigt, die einfach verknüpfte Listen der libglib zur Verfügung stellt (Zeile 11). In Zeile 19 wird die bereits erwähnte Funktion \emph{gtk\_stocklist\_ids} aus der \emph{libgtk} in das Vokabular \emph{gtk api} importiert. Der Viewer ist ein Beispiel für die Verwendung der Klasse \emph{GtkComboBoxText}. Für den Viewer legen wir deshalb ein privates Vokabular im Kontext (in der Wortliste) dieser Klasse an (Zeile 22 u. 24). Privat bedeutet hier, dass das Vokabular für Objekte der Klasse nicht sichtbar ist. % \begin{figure*}[th] \begin{center} \includegraphics[scale=0.45]{2008-03/Terminal} \caption{\label{fig:Status} Status nach dem Laden von Listing 1} \end{center} \end{figure*} In den Zeilen 26 bis 34 werden die für den Viewer benötigten Objekte definiert: \begin{description} \item [{GtkToplevel}] Ein GtkWindow des Typs GTK\_WINDOW\_TOPLEVEL. \item [{GtkTable}] Ein Container-Widget, in das andere Widgets in Zeilen und Spalten gepackt werden können. \item [{GtkLabel~Array}] Ein Array, dessen Elemente Objekte der Klasse \emph{GtkLabel} (Beschriftungen) sind. \item [{GtkAlignment~Array}] Ein Array, dessen Elemente Objekte der Klasse \emph{GtkAlignment} sind. Ein Objekt der Klasse GtkAlignment ist ein GtkContainer-Widget, in das man ein anderes Widget packen kann, das horizontal und vertikal ausgerichtet werden kann. \item [{GtkCombBoxText}] Ein \emph{GtkButton} (Knopf), der mit einer Liste von Textelementen verbunden ist, die sich auf Knopfdruck öffnet und aus der man genau ein Element auswählen kann. Das ausgewählte Element wird als Knopfbeschriftung angezeigt. \item [{GtkImage}] Ein GtkWidget zur Anzeige eines Bildes, dem das Icon des ausgewählten GtkStockItems zugewiesen werden soll. \item [{GtkButton}] Ein Knopf, der mit den Eigenschaften des ausgewählten GtkStockItems dargestellt werden soll. \item [{GSList}] Eine einfach verknüpfte Liste für die Handhabung der GTK Stock Ids. \end{description} In Zeile 37 wird ein Signalhandler \emph{cb.quit} definiert, der aufgerufen werden soll, wenn das Hauptfenster \emph{window} geschlossen wird. In den Zeilen 39 bis 42 wird ein Signalhandler \emph{cb.changed} definiert, der ausgeführt werden soll, wenn mit der GtkComboBox ein Listenelement ausgewählt worden ist. Der Handler liest das ausgewählte Element aus der GtkComboBox \emph{combo} (Zeile 40) aus und weist es dem GtkButton \emph{button} und dem GtkLabel \emph{label} zu. Die Zeilen 44 u. 45 legen Optionen fest, mit denen die Elemente des GtkLabel-Arrays und des GtkAlignment-Arrays in das GtkTable-Widget gepackt werden sollen. In Zeile 49 beginnt die Initialisierungsroutine des Viewers. Sie initialisiert die in den Zeilen 26 bis 34 definierten Objekte, erzeugt die Widgets, packt sie in ihre Container und zeigt dann das Hauptfenster an. In Zeile 49 wird das Hauptfenster des Viewers initialisiert. Die \emph{init}-Methode erzeugt ein GtkWindow vom Typ GTK\_TOPLEVEL\_WINDOW und weist diesem den String, der auf dem Stack übergeben wird, als Titel zu. In Zeile 50 erhält das Fenster einen inneren Rand von 12 Pixel und es wird festgelegt, dass die Fenstergröße vom Anwender nicht geändert werden kann. In Zeile 51 werden das \emph{destroy}-Signal und der in Zeile 37 definierte Callback-Handler \emph{cb.quit} an das Hauptfenster gebunden. Damit wird festgelegt, dass \emph{cb.quit} ausgeführt wird, wenn das Fenster vom Fenstermanager ein \emph{destroy}-Signal erhält. In Zeile 53 wird das GtkTable-Widget \emph{table} initialisiert und in das Hauptfenster \emph{window} gepackt. Anschließend wird in Zeile 54 der Spalten- und Zeilenabstand auf 8 Pixel festgelegt. Die Tabellengröße muss nicht angegeben werden. Sie wird automatisch angepasst, wenn Widgets in die Tabelle gepackt werden. In den Zeilen 56 bis 60 werden die Beschriftungen (GtkLabels) initialisiert und in die erste Spalte des GtkTable-Widgets gepackt. Die drei Beschriftungen sind Elemente des Arrays \emph{labels,} das in Zeile 28 definiert wurde. Die Initialisierung des Arrays erfolgt in zwei Schritten. Zuerst wird seine Größe festgelegt (Zeile 56), danach werden dann seine Elemente initialisiert (Zeile 57-59). Die \emph{init}-Methode der Klasse GtkLabel erwartet den Text, der als Beschriftung angezeigt werden soll, als String auf dem Stack. Sie erzeugt ein GtkLabel-Widget und gibt dessen Adresse - in Forth \emph{widget identifier (wid)} genannt - auf dem Stack zurück. Diese Adresse wird von der \emph{attach}-Methode der Klasse GtkAlignment verwendet, um das GtkLabel-Widget in die erste Spalte des GtkTable-Widgets \emph{table} zu packen. In Zeile 60 werden dann die Beschriftungen in der ersten Spalte des GtkTable-Widgets \emph{table} rechtsbündig ausgerichtet. In den Zeilen 62 u. 63 wird das in Zeile 29 definierte GtkAlignment-Array initialisiert. Seine drei Elemente (GtkAlignment-Widgets) werden in die zweite Spalte des GtkTable-Widgets \emph{table} gepackt. In die GtkAlignment-Widgets werden dann das GtkComoBox-Widget \emph{combo}, das GtkImage-Widget \emph{imag}e und das GtkButton-Widget \emph{button} gepackt (Zeile 64-67) und linksbündig ausgerichtet (Zeile 68). In den Zeilen 70 bis 74 wird die von der Funktion gtk\_stock\_list\_ids übergebene Liste der GTK Stock Ids in die GtkComboBox eingetragen. Alle Widgets sind nun erzeugt, aber noch nicht zu sehen. Sie werden durch den Code in Zeile 77 sichtbar gemacht. In Zeile 84 wird der Viewer gestartet. Wurde der cspForth-Prozess, der den Code ausführt, in einem Terminal gestartet, zeigt das Wort \emph{??} den aktuellen Zustand des Forth-Systems an (Abbildung \ref{fig:Status}). Mit cspForth kann dann interaktiv gearbeitet werden und man kann auf die Widgets des Viewers zugreifen. Die Verarbeitung der Gtk-Ereignisse erfolgt im Hintergrund, während auf die Eingabe einer Kommandozeile gewartet wird. Ist der cspForth-Prozess nicht mit einem Terminal verbunden, gibt es keine Ereignisverarbeitung im Hintergrund. Es muss dann eine GTK\texttt{+}-Hauptschleife gestartet werden ({[}ELSE]-Zweig in Zeile 84), die auf Ereignisse wartet und dann den zugeordneten Code ausführt. Sie wird erst wieder verlassen, wenn der Callback-Handler cb.quit beim Schließen des Hauptfensters ausgeführt wird. \begin{thebibliography}{1} \bibitem{key-1}GTK+-Dokumentation. http://www.gtk.org \bibitem{key-2}Matthias Warkus: GNOME 2.0 - Das Entwickler-Handbuch. Galileo Press, 2003 \bibitem{key-3}Manfred Mahlow: Widgets zum Anfassen - GUI-Skripting mit Forth und GTK+. Vierte Dimension 2/2008 \end{thebibliography} %\appendix %\onecolumn \end{multicols} \section*{Listing 1:} \begin{lyxcode} ~~~1~~\textbackslash{}~GtkComboBoxText/example.2.4th ~~~2~~ ~~~3~~~~needs~GtkToplevel ~~~4~~~~needs~GtkTable ~~~5~~~~needs~GtkLabel~Array ~~~6~~~~needs~GtkAlignment~Array ~~~7~~~~needs~GtkComboBoxText ~~~8~~~~needs~GtkImageFromStock ~~~9~~~~needs~GtkButton ~~10~~ ~~11~~~~needs~GSList ~~12~~ ~~13~~\textbackslash{}~-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}- ~~14~~\textbackslash{}~~csp4th~:~~GtkComboBox~Example~2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MM-080311 ~~15~~\textbackslash{}~-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}- ~~16~~ ~~17~~~~gtk~api~definitions ~~18~~ ~~19~~~~libgtk~import~gtk\_stock\_list\_ids~(~-{}-~{*}list~) ~~20~~ ~~21~~ ~~22~~~~GtkComboBoxText~definitions ~~23~~ ~~24~~~~private~vocabulary~example.2~~self~example.2~definitions~~also~gtk~api ~~25~~ ~~26~~~~GtkToplevel~~~~~~~~new~window ~~27~~~~GtkTable~~~~~~~~~~~new~~table ~~28~~~~GtkLabel~Array~~~~~new~~~labels ~~29~~~~GtkAlignment~Array~new~~~alignments ~~30~~~~GtkComboBoxText~~~~new~~~~combo ~~31~~~~GtkImage~~~~~~~~~~~new~~~~image ~~32~~~~GtkButton~~~~~~~~~~new~~~~button ~~33~~ ~~34~~~~GSList~new~list ~~35~~ ~~36~~ ~~37~~~~::~(~wid~data~-{}-~)~2drop~gtk~quit~;~~2~20~cb~cb.quit ~~38~~ ~~39~~~~::~(~wid~data~-{}-~) ~~40~~~~~~~2drop~combo~@~dup~if ~~41~~~~~~~~~2dup~image~from-stock~button-size~!~~button~label~! ~~42~~~~~~~then~;~~2~20~cb~cb.changed ~~43~~ ~~44~~~~:~\%label~(~-{}-~xopts~yopts~xpad~ypad~)~~~~~GTK\_FILL~0~~0~0~; ~~45~~~~:~\%alignment~(~-{}-~xopts~yopts~xpad~ypad~)~GTK\_FILL~0~12~0~; ~~46~~ ~~47~~~~:~viewer~(~-{}-~) ~~48~~~ ~~49~~~~~~~~\char`\"{}~Gtk~Stock~Item~Viewer\char`\"{}~window~init ~~50~~~~~~~~12~window~border-width~!~~~window~resizable~off ~~51~~~~~~~~\char`\"{}~destroy\char`\"{}~cb.quit~0~window~signal~connect~drop ~~52~~ ~~53~~~~~~~~table~init~~window~add ~~54~~~~~~~~8~table~column-spacing~!~~8~table~row-spacing~! ~~55~~ ~~56~~~~~~~~3~labels~init ~~57~~~~~~~~\char`\"{}~Stock~Item:\char`\"{}~0~labels~of~init~~0~1~0~1~\%label~table~attach ~~58~~~~~~~~\char`\"{}~Image:\char`\"{}~1~labels~of~init~~~~~~~0~1~1~2~\%label~table~attach ~~59~~~~~~~~\char`\"{}~Button:\char`\"{}~2~labels~of~init~~~~~~0~1~2~3~\%label~table~attach ~~60~~~~~~~~3~0~do~i~labels~of~xalign~right~loop ~~61~~ ~~62~~~~~~~~3~alignments~init ~~63~~~~~~~~3~0~do~i~alignments~of~init~~1~2~i~dup~1+~\%alignment~table~attach~loop ~~64~~~~~~~~combo~init~~0~alignments~of~add ~~65~~~~~~~~\char`\"{}~changed\char`\"{}~cb.changed~0~combo~signal~connect~drop ~~66~~~~~~~~\char`\"{}~?\char`\"{}~image~from-stock~button-size~init~~1~alignments~of~add ~~67~~~~~~~~\char`\"{}~?\char`\"{}~button~init~~2~alignments~of~add ~~68~~~~~~~~3~0~do~i~alignments~of~xalign~left~loop ~~69~~ ~~70~~~~~~~~gtk\_stock\_list\_ids~list~init ~~71~~~~~~~~~~list~size~dup~1-~swap~0~do ~~72~~~~~~~~~~~~dup~i~-~list~of~@~dup~zcount~combo~append~~free ~~73~~~~~~~~~~loop~drop ~~74~~~~~~~~list~free ~~75~~~~~~~~0~combo~activate ~~76~~ ~~77~~~~~~~~window~show~all ~~78~~~~; ~~79~~ ~~80~~~~hide~cb.quit~~hide~cb.changed ~~81~~ ~~82~~~~previous ~~83~~ ~~84~~~~viewer~term?~{[}IF]~??~{[}ELSE]~gtk~main~bye~{[}THEN] ~~85~~\textbackslash{}~-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}- ~~86~~\textbackslash{}~Last~revision:~MM-080525 ~ \end{lyxcode} \vfill \begin{center} \includegraphics[height=7cm]{2008-03/profile-of-time}\\ Salvador Dali: \emph{Profil der Zeit}\\ Die Bronze ist im \emph{Arkady Wrocławskie} Einkaufszentrum in Breslau ausgestellt.\\ (Photo: Wikimedia/Julo, 4/2008) \end{center} \vfill \end{document}