Entwickeln mit ACS, Teil 1

Wer die letzte Ausgabe der ST-Computer gelesen hat, dem wird sicher der Testbericht zu einem neuartigen Programm aufgefallen sein: ACS (Application Construction System) genannt, soll dieses Entwicklungssystem die Erstellung der Benutzeroberflächen unter GEM erheblich erleichtern. Was der Test nicht klar zeigen konnte, wird in dieser Artikelreihe dem Leser nahegebracht - der praktische Umgang mit diesem leistungsfähigen Entwicklungs-Tool. Dabei wenden wir uns sowohl an absolute Anfänger als auch an Profis.

Damit diese Artikel nicht allzu theoretisch ausfallen, sollten Sie sich, falls Sie das Programm nicht besitzen, eine Demoversion (s. Demodisk D83 in dieser Ausgabe) besorgen.

Bevor wir anfangen, gilt es noch einige grundsätzliche Dinge zu klären. Als Voraussetzung für erfolgreiches Programmieren unter ACS müssen Sie die Programmiersprache C beherrschen und einen Turbo- oder Pure-C-Compiler besitzen. Ihre C-Kenntnisse dürfen sich allerdings in Grenzen bewegen, denn die komplexeren Konstrukte werden wir alle erklären. Auch wird nicht vorausgesetzt, daß Sie bereits Erfahrung mit der Programmierung unter GEM haben, Sie sollten aber bereits wissen, wie man mit dieser Oberfläche umgeht.

GEM

Graphics Environment Manager (GEM) ist der Teil des Betriebssystems Ihres Atari, der die Kommunikation zwischen Benutzer und Programm mit Hilfe von grafischen Elementen vereinfacht und standardisiert. Da es immer noch Programmierer gibt, die sich nicht an diesen Standard halten, und da ACS GEM in einigen Punkten erweitert, sollen hier die einzelnen Bedienungselemente noch einmal aufgezählt und ihre Bedeutung erklärt werden.

In der Hierarchie am höchsten ist das Desktop. Das ist eigentlich der gesamte sichtbare Bereich des Bildschirms. Es enthält eine Menüleiste und bietet Platz für diverse andere Elemente wie zum Beispiel Fenster oder Icons. Auf dem Atari war es bisher so, daß jedes Programm seinen eigenen Desktop und die dazugehörige Menüleiste besaß. Unter ACS ist es jedoch üblich, das von der Laufzeitumgebung bereitgestellte Default-Desktop zu verwenden. Dieses verwaltet von Haus aus eine nicht veränderbare Menüleiste und auf dem Bildschirm plazierbare Icons, die einzelne ACS-Fenster repräsentieren. Auf den ersten Blick scheint dies eine merkwürdige Einschränkung zu sein, entledigt sie aber von lästigen Verwaltungsaufgaben und stellt sich als äußerst sinnvoll heraus, da Menüleisten allemal in die Fenster gehören. Allen denjenigen, die sich unbedingt mehr Arbeit machen wollen, sei gesagt, daß es möglich ist, ein eigenes Desktop einzubinden.

Bild 1: Der ACS-Editor

Menüleisten sind sicher jedem von Ihnen bekannt. Zu unterscheiden gilt es noch die Drop-Down- und die Pull-Down-Menüleisten. Erstere sind die bis jetzt üblichen, die bereits beim Eintritt der Maus in ihren Bereich herunterklappen, letztere müssen erst angeklickt werden. Sie werden sie in Fenstern antreffen, wo es meist sinnvoller ist, erst auf ausdrücklichen Wunsch des Benutzers zu warten. Manche der Einträge, die sich unter einem der Titel befinden, können auch über Tastenkombinationen aktiviert werden. Die Tastenkombination steht dann hinter dem Eintrag und hält sich an einen vorgeschriebenen Standard.

Neu hinzugekommen sind die bekannten Pop-Up-Menüs. Sie haben einen hierarchischen Aufbau, der beliebig tief schachtelbar ist, und können wie normale Menüleisten auch, Bilder (Images) enthalten. Ihre Verwendung ist sehr vielseitig, und es ist nicht streng definiert, wo sie zu verwenden sind. Es empfiehlt sich aber, sie auf schattierte Buttons zu legen (mehr dazu in einer späteren Folge).

ACS-Fenster unterscheiden sich von den bekannten GEM-Fenstern in einigen Punkten, was aber nicht ihr Aussehen oder ihre Funktion betrifft. Der Unterschied liegt darin, daß ACS-Fenster oft nur durch ein Icon auf dem Desktop repräsentiert werden, das erst durch einen Doppelklick zu einem GEM-Fenster wird. Ein Grund dafür liegt bei GEM, denn es begrenzt die Anzahl offener Fenster. Dieses Verhalten von ACS-Fenstern ist aber (wie vieles andere) nicht zwingend und kann an die Wünsche des Anwenders angepaßt werden.

Bild 2: Der Fenster-Editor
Bild 3: Ein wichtiges Pop-Up-Menü

Auch die Dialogboxen sind in vieler Hinsicht verbessert worden. So ist es von nun an üblich, Dialoge in Fenster auszugeben, damit diese nicht erst beendet werden müssen, bevor anderes erledigt werden kann. Dies geht sehr bequem vonstatten, denn es erfolgt ohne Zutun des Programmierers.

Die einzelnen GEM-Objekte wie Buttons, Strings oder Boxen müssen hier nicht besonders erläutert werden. Es sind aber einige neue Objekte hinzugekommen. So zum Beispiel die runden Radio- und die Checkbuttons, die Ihnen bereits bekannt sein dürften. Daneben existiert ein neuer Rahmen, Innerframe genannt, der zum optischen Zusammenfassen zusammenhängender Objekte dient. Auf der oberen Kante kann eine Überschrift plaziert werden, die beim Verschieben des Innerframes mitverschoben wird. Seit der Version 1.02 sind noch zwei Objekte hinzugekommen, die eine eher geringe Bedeutung haben. Es sind dies eine Box, die ein Muster (die bekannten VDI-Muster) enthalten kann, und eine frei definierbare Linie, die auch als Pfeil agieren kann.

Die Anfänge

ACS ist eine Weiterentwicklung des Resource Construction Sets (RCS). Es besteht aus zwei Teilen: einem grafischen Editor und einer Laufzeitumgebung, die zum Beispiel das Aussehen des Default-Desktops bestimmt und die Routinen enthält, die die Verwaltung des laufenden Programms übernehmen. Der Programmierer muß in dem Editor das Aussehen seiner Bedieneroberfläche definieren beziehungsweise zeichnen, denn die Aufgabe ähnelt dem Zeichnen mit einem objektorientierten Zeichenprogramm. Zusätzlich werden hier aber auch Verbindungen (Referenzen) zum eigentlichen Programm angegeben, beispielsweise der Name der Routine, die ausgeführt werden soll, wenn der Benutzer einen Menüeintrag ausgewählt hat. Diese Definitionen werden in Dateien gespeichert, die den Resource-Dateien ähneln, die mit einem RCS erstellt wurden. Anders als dort, werden diese aber nicht für das Programm benötigt. Vielmehr erstellt der ACS-Editor auf Wunsch die zur Programmierung benötigten Header-Dateien. Man hat dabei die Wahl zwischen C oder DR-Objektcode als Ausgabeform. Für unsere Zwecke eignet sich die Ausgabe der C-Datei am besten.

Bild 4: Das erste Work-Objekt

Um Ihnen einen kleinen Überblick über die Arbeit mit dem ACS-Editor zu geben, werden wir uns hier anschauen, was unbedingt gemacht werden muß, damit ein kleines GEM-Programm zum Laufen gebracht wird. Und da Applikationen unter ACS durch Fenster repräsentiert werden, soll eines erzeugt werden. Dazu laden Sie den ACS-Editor und öffnen eine neue Datei mit dem Namen FIRST.ACS zum Bearbeiten, indem Sie den entsprechenden Menüeintrag anwählen. In dem darauf erscheinenden Generelles-Fenster (Bild 1) sehen Sie unter anderem ein Fenster-Icon.

Bild 5: So trägt man Objekte in die Fensterstruktur ein.
Bild 6: Unser erstes GEM-Programm

Ein einfacher Mausklick darauf öffnet die Fensterliste, in der Sie alle bis jetzt erstellten Fenster finden. Schieben Sie das Neu-Icon, das sich auf dem Desktop befindet, in diese Fensterliste, um ein neues Fenster zu erzeugen. Als Name tragen Sie ein Wort ein, das Sie leicht mit dem Fenster assoziieren können, denn es wird nachher im Listing gebraucht. In unserem Beispiel soll das Fenster TEXTFENSTER heißen. In der Fensterliste befindet sich jetzt ein Icon mit dem selben Namen (Bild 1). Führen Sie einen Doppelklick auf dieses aus, um den Fenster-Editor zu öffnen (Bild 2). Hier kann das Aussehen und Verhalten des Fensters festgelegt werden. Die Position und das Raster sind vorerst unwichtig. Bei den Komponenten und Fenstertexten können Sie sich an Bild 2 orientieren, Sie können aber auch mit anderen Kombinationen experimentieren. Am rechten Rand des Fenster-Editors befindet sich ein Scroll-Balken, mit dem Sie zu weiteren Eingabefeldern gelangen. Die Fensterobjekte legen fest, ob, und wenn, welche Menüleiste und Work-Objekte innerhalb des Fensters dargestellt werden, welches Icon das Fenster auf dem Desktop repräsentieren soll (falls hier nichts angegeben wird, verwendet ACS ein Default-Icon). Das Workobjekt ist das Fensterinnere und kann zum Beispiel auch eine Dialogbox sein. Wie man hier Daten einträgt, sehen Sie weiter unten, nachdem wir ein Workobjekt erzeugt haben werden. Bleiben noch die Fensterroutinen, die abweichendes Verhalten gegenüber den Default-Routinen festlegen. Die Arbeitsweise hier entspricht dem Überladen (Overloading) bei objektorientierten Programmiersprachen. Die einzige Funktion, die wirklich geschrieben werden muß, ist CREATE, die Routine also, die ein Fenster erzeugt. Tragen Sie für unser Beispiel text_create ein. Mit einem Druck auf die Return-Taste oder einem Klick auf den OK-Button beenden Sie den Fenster-Editor.

Holen Sie das Generelles-Fenster wieder vor und klicken das Objekt-Icon an. Wir befinden uns in der Objektliste. Erzeugen Sie nun, wie oben, ein neues Objekt mit dem Namen TEXTFELD und öffnen Sie dieses. Neben einem Objekteditor- öffnet sich auch ein Teilefenster. Dies ist eine Toolbox mit allen verfügbaren Objekttypen. Im Objekteditor befindet sich eine leere (Dialog-)Box. Ein einfacher Klick selektiert diese, und indem Sie mit der Maus das nun entstandene schwarze Feld bewegen, können Sie die Größe der Box einstellen. Ein Doppelklick hingegen bringt ein Pop-Up-Menü zutage (Bild 3). Der Eintrag Specs ermöglicht die Eingabe objektspezifischer Daten: bei einem String ist es zum Beispiel der Text, bei unserer Box die Art des Rahmens oder die Farbe. Stellen Sie hier einen Rahmen mit der Dicke Null ein. In der linken oberen Ecke sehen Sie übrigens das Endergebnis dargestellt. Beenden Sie den Dialog mit OK. Nun ziehen Sie aus der Toolbox einen String auf unsere Box. Dazu klicken Sie das Teilefenster an oder - damit Sie sich zwei Mausklicks sparen -drücken Sie vor der linken Maustaste die rechte, um ein Objekt eines nicht getoppten Fensters anzuwählen. Wie bei der Box können Sie auch beim String die Größe und die Specs ändern. In Bild 4 sehen Sie die fertige Box. Beenden Sieden Objekt-Editor, indem Sie das Schließfeld des Fensters anklicken.

Diese Box wollen wir nun als Work-Objekt in den Fenster-Editor eintragen. Öffnen Sie dazu wieder den Fenster-Editor und schieben, wie in Bild 5 gezeigt, das Textfeld-Icon in den Editor. Bei dem Eintrag WORK steht nun TEXTFELD. Wählen Sie nun den Menüeintrag Sichern an, den Sie im Generelles-Fenster unter Datei finden und unter Ausgabe ANS1-C. Nun können Sie den ACS-Editor verlassen. Das Ganze in Text gefaßt sieht sicher schwieriger aus, als es ist. Diejenigen, die bereits Erfahrung mit einem RCS gesammelt haben, werden mir diesen weitschweifigen Ausflug sowieso nicht verzeihen.

Tippen Sie Listing 1 und 2 ab, passen diese an die eigene Entwicklungsumgebung an und compilieren sie mit dem C-Compiler. Eventuelle Warnungen wie parameter ... never used sollten Sie dabei nicht stören. Nach erfolgreichem Übersetzungslauf und Start befinden Sie sich im Default-Desktop. Wählen Sie den Eintrag Öffnen, und es wird ein Fenster mit Ihrer ersten GEM-Applikation unter ACS geöffnet (Bild 5). Sie können nahezu beliebig viele Fenster auf diese Art öffnen. Nachdem die Funktion überprüft wurde, können Sie mit verschiedenen Werten im Fenster- und Verhaltens-Editor experimentieren.

Bild 8: So wird die Dialogbox aufgebaut.
Bild 7: Die fertige Dialogbox

Das Programm

Listing 1 soll kurz besprochen werden. Das erste Include mischt die allgemeine Header-Datei von ACS in unser Programm (passen Sie den Pfad dieser Datei an Ihre Entwicklungsumgebung an). Diese enthält die Definitionen und Deklarationen wichtiger Strukturen und Funktionen. Danach müssen alle Routinen, die im ACS-Editor angegeben wurden, durch Prototypen deklariert werden. Es ist ganz praktisch, so weit es geht, statische Funktionen zu verwenden. Erst jetzt wird die von ACS erzeugte Datei (FIRST.AH) eingemischt. Diese drei Schritte müssen unbedingt in der selben Reihenfolge auftreten, damit der Compiler keine Schwierigkeiten bekommt.

Die Funktion ACSinit muß definiert werden und erledigt Dinge wie zum Beispiel die Initialisierung eigener Datenstrukturen oder aber die Anmeldung einer Routine, die ausgeführt werden soll, wenn der Benutzer das Neu-Icon anklickt. Da sich das Desktop auch als ein Fenster verhält, bekam es den Namen Root-Fenster. Die globale Menüleiste und die Icons vom ACS-Desktop gehören zu diesem Root-Fenster. Der C-Typ eines ACS-Fensters ist Awindow. Dies ist eine Struktur, die alle wichtigen Informationen zu einem Fenster enthält, so zum Beispiel auch, an welchen Koordinaten es sich befindet, oder welche Routine aufgerufen wird, wenn ein neues Fenster erzeugt werden soll. Hat man einmal die Adresse dieser Struktur, so kann man alles nur Erdenkliche mit dem zugehörigen Fenster tun. Wenn wir es öffnen möchten, benutzen wir dazu folgende C-Zeile:

(window->open)(window);

wobei window die Adresse der Fensterstruktur ist. Um die Adresse der Root-Fenster-Struktur zu erhalten, bedienen wir uns der AvW_root-Funktion, die sich in der mitgelieferten Bibliothek befindet (siehe Listing 1). Mit

(rootwindow->service)(rootwindow, AS_NEWCALL, &TEXTFENSTER.create);

geben wir dem Root-Fenster bekannt, daß unsere CREATE-Routine aufgerufen werden soll, wenn ein Doppelklick auf das New-Icon getätigt wird. Der Rückgabeparameter der Funktion ACSinit ist OK, falls alles in Ordnung war, FAIL sonst.

Fehlt nur noch text_create, unsere CREATE-Routine. Wir erzeugen mit der Default-Funktion Awi_create ein neues Fenster, d.h., daß eine neue Fensterstruktur angelegt beziehungsweise von TEXTFENSTER kopiert und ein Fenster-Icon auf dem Desktop plaziert wird. Hätten wir im Fenster-Editor nicht unsere CREATE-Routine eingetragen, würde automatisch Awi_create ausgeführt werden. Wir wollen aber, daß das Fenster sofort geöffnet wird.

(window->open)(window);

öffnet das Fenster window. Da wir aber keine eigene OPEN-Routine definiert haben, wird hier Awi_open - die Default-Routine für das Öffnen - angesprungen. Daher hätten wir ebenso gut

Awi_open(window);

schreiben können. Genauere Informationen über die mitgelieferten Routinen und über die Fensterstruktur bekommen Sie in der nächsten Folge.

Eine Dialogbox

Wir haben zwar bereits ein GEM-Objekt innerhalb eines Fensters dargestellt, dieses konnte aber nicht auf Benutzeraktionen reagieren, deshalb wollen wir uns noch anschauen, wie eine vollwertige Dialogbox erstellt und verwaltet wird. Die Box soll einige Einstellungen ermöglichen und diese, falls der JA-Button angeklickt wurde, in einer globalen Variablen speichern. Sollte der Benutzer NEIN angewählt haben, wird die Dialogbox zwar auch geschlossen, die Werte werden aber nicht übernommen. Schließlich soll ein RESET-Button die Rücksetzung der Einstellungen in ihren Ursprungszustand ermöglichen. Das Aussehen der fertigen Dialogbox sehen Sie in Bild 7.

Wie im ersten Beispiel, erstellen wir auch hier ein Fenster mit dem Namen DIALOGFENSTER. Seine Komponenten beschränken sich auf den Namen und die obere Fensterleiste, die zum Bewegen dient (NAME und MOVE). Die CREATE-Routine heißt dialog_create. Als Work-Objekt tragen Sie das Objekt DIALOG wie oben schon beschrieben ein. Dazu muß dieses erst erstellt werden. Bild 8 zeigt Ihnen, welche Objekte Sie dafür benötigen. Ziehen Sie die Objekte in der gezeigten Reihenfolge (die Objekte sind in der Bild 8 numeriert) aus dem Teilefenster und passen sie gleich in der Größe an. Die Art der Umrahmung und den Text der Buttons können Sie unter Specs ändern. Jetzt werden auch andere Bereiche des Pop-Ups in Bild 3 wichtig. Dit Flags (Bild 9) enthalten wichtige Informationen wie zum Beispiel, ob ein Objekt editierbar, selektiert oder mit dem Exit-Status behaftet ist. Der Exit-Status (EXIT oder TOUCHEXIT) gibt an, daß die Programmausführung bei Anwählen dieses Objekts dem Programmierer überlassen wird, damit dieser entsprechende Aktionen ausführen kann. Buttons sind Beispiele für Objekte mit diesem Status. ACS schaut unter Refs (Bild 10), um die Routine zu finden, die beim Anklicken ausgeführt werden soll. Neben der Reaktion auf die Maus kann auch auf die Taste reagiert werden, die unter Taste eingetragen ist.

Nun wollen wir unsere Objekte mit den korrekten Flags und Refs ausstatten. Von den Radio-Buttons sollte einer - und nur einer! - selektiert sein (SELECTED); die anderen Einstellungen setzt ACS automatisch. Unter Refs bekommt jeder Radio-Button einen Index, damit sie nachher im Programm unterschieden werden können. Wählen Sie hier die Index-Namen OPTION1, OPTION2 und OPTION3 für die Buttons von oben nach unten. Entsprechend tragen Sie unter Taste 1,2 und 3 ein. Die Checkbuttons sind nicht selektiert, haben den Index CHECKA und CHECKB und die Taste A beziehungsweise B. Bleiben noch die Buttons JA, NEIN und RESET. Kreuzen Sie unter Flags neben den bereits angewählten Optionen noch DEFAULTABLE und bei JA auch noch DEFAULT an. Der Default-Button ist der, der angewählt wird, wenn die Return-Taste gedrückt wurde. Es ist der Button, der im Zusammenhang am logischsten erscheint oder am wenigsten zerstören kann. Indem alle drei Buttons den Status DEFAULTABLE bekamen, kann sich der Benutzer selbst einen Default-Button auswählen, wenn er sich der Tastenkombination Control+Tab bedient. Bei Refs tragen wir noch unter Click unsere Routine ein, bei JA zum Beispiel ja_click und noch die passende Taste (z.B. J). Das gleiche gilt für NEIN und RESET entsprechend. Damit wäre unsere grafische Definition abgeschlossen. Speichern Sie sie unter dem Namen DIALOG ab.

Bild 9: Flags zu einem Radio-Button
Bild 10: Referenzen des „JA“-Buttons

Das Programm sehen Sie in Listing 3. Compilieren Sie dieses mit der zugehörigen Projektdatei aus Listing 4. Wenn Sie sich das Programm anschauen, werden Sie bemerken, daß neben der Datei DIALOG.AH auch DIALOG.H eingemischt wird. In dieser Datei sind die Indizes gespeichert, die wir vorhin definiert haben. DATA enthält den Zustand der Einstellungen der Dialogbox. Diese werden in der globalen Variablen global_data gespeichert, dialog_create erzeugt ein neues Fenster und öffnet es gleich. Davor wird noch der Zustand der Einstellungen zurückgesetzt (wi->work zeigt auf das Work-Objekt). Beim Initialisieren wird, zusätzlich zu den üblichen Aktionen, die globale Variable zurückgesetzt.

Die nun folgenden Funktionen, die unter Click eingetragen wurden, besitzen alle dasselbe Format: sie bekommen keine Parameter und geben auch keine zurück. Damit der Programmierer aber trotzdem Zugriff auf wichtige Daten hat, gibt es einige globale Variablen. In unserem Listing finden Sie ev_window und ev_object, die die Adresse auf das aktuelle Fenster beziehungsweise Objekt enthalten.

Die Aufgabe der Funktion ja_click ist zu schauen, welche Einstellungen selektiert sind, und diese dann in unserer Variable zu speichern. Wir gehen alle selektierten Objekte in der Dialogbox durch und vergleichen deren Indizes mit denen unserer Objekte. Sollte eine Übereinstimmung festgestellt werden, muß sie in die Variable eingetragen werden. Die Bibliotheksfunktion Aob_findflag ist für diese Aufgabe prädestiniert. Nachdem alle Buttons überprüft wurden, wird die Box (das Fenster) geschlossen.

Sind die Änderungen falsch, wählt der Benutzer NEIN, nein_click muß also die Werte restaurieren. Die korrekten befinden sich in der globalen Variablen. Dazu werden alle Einstellungen deselektiert (reset_dialog und die Zeile danach). Nun können die Werte der Variablen übernommen werden. Auch hier wird das Fenster geschlossen.

Bleibt noch reset_click. Die Funktion setzt die Einstellungen zurück und zeichnet das Objekt neu, damit die Änderungen sichtbar werden. Die Funktion, die hier verwendet wird (Awi_obredraw), ist erst seit der Version 1.02 verfügbar. Wenn Sie eine ältere Version von ACS besitzen, müssen Sie Awi_obchange verwenden.

So, hiermit wäre der Einstieg in die Entwicklung mit ACS geschafft. Sicher haben Sie hier und da einige Dinge nicht verstanden, der grobe Zusammenhang dürfte aber hervorgetreten sein. Meine Absicht war vor allem, Sie zu motivieren, mehr über die GEM-Programmierung erfahren zu wollen, damit in endlich viel Zeit alle Programme unter GEM arbeiten werden. Das nächste Mal werden wir eine richtige Applikation mit neuen Schwierigkeitsmomenten entwickeln. Bis dann.


Grischa Ekart
Links

Copyright-Bestimmungen: siehe Über diese Seite