von Michael Christoph
Nachdem wir in den letzten beiden Kursfolgen die Grundlagen für die Programmierung unter AmigaOS 3.5 gelegt haben, wollen wir in diesem Monat noch tiefer in die Praxis einsteigen und eigene Gadgets programmieren.
Wieso eigene Gadgets erstellen?
|
Es besteht zwar auch die Möglichkeit, C++ den Klassen zu verwenden oder entsprechen Source-Code zu kopieren, aber in Punkto Weiterentwicklung/Anpassungen funktioniert es mit einem eigenen Gadget am besten. Zwar profitieren bei Klassen in C++ auch alte Programme von Neuerungen (wenn die Klasse zentral abgelegt wird), dann aber erst durch Neucompilieren. Ist das Programm öffentlich oder frei verfügbar, müssen andere Personen sich erst die neue Version besorgen. Das wird durch unterschiedliche Programmversionen ect. erschwert.Wird dagegen nur ein Gadget ausgetauscht, ist das normalerweise ohne weiteren Aufwand möglich. Im Hinblick auf das reine Kopieren von Source sind Änderungen kaum rückportierbar. Dadurch sind ältere Programme evtl. wegen dieses Fehlers nicht mehr oder nur noch eingeschränkt nutzbar.
Auf der anderen Seite haben die externen Gadgets den Vorteil, daß der Programmcode kleiner und überschaubarer ausfällt, was auch der Fehlerreduzierung zugute kommt. Kommt das Gadget in mehreren Programmen zum Einsatz, wird es auch mehrfach in unterschiedlichen Umgebungen getestet. Aufgedeckte Fehler werden zentral im Gadget beseitigt. und alle anderen Programme profitieren sofort von der Verbesserung.
Class *CreateExampleGClass(void) { Class *clas; if(clas = MakeClass(NULL,GADGETCLASS,NULL, sizeof(struct ExampleGData),0)) { clas->cl_Dispatcher.h_Entry = (ULONG (*)()) ExampleGDispatcher; clas->cl_Dispatcher.h_SubEntry = NULL; } return( clas ); } Listing 1: Erste Schritte, um ein eigenes Gadget zu erzeugen. |
Grundlagengerüst
Die Gadget-Klassen basieren auf dem Library-Konzept und werden erst während
der Laufzeit nachgeladen, wenn sie angefordert werden. Damit fügen sie sich sehr
gut in das speichersparende AmigaOS ein. Wie bei Libraries auch, werden sie über
die Open/Close/Expange-Funktion bedient.
Open: wird jedesmal aufgerufen, wenn ein Programm dieses Gadget anfordert (OpenLibrary: Counter für die Benutzung wird hochgezählt).
Close: wird jedesmal aufgerufen, wenn ein Programm das Gadget wieder freigibt (CloseLibrary: Benutzercounter wird verringert).
Auf den zugewiesenen Funktionszeiger (Dispatcher) wird weiter unten eingegangen. Soll es sich um eine öffentliche Klasse handeln, die von jedem Programm direkt über den Namen angesprochen werden kann, so ist dieser Name als erster Parameter von MakeClass() anzugeben (ohne die .gadget-Endung) und per AddClass (class) der Systemliste hinzuzufügen. Öffentliche Namen sollten allerdings nur System-Gadgets oder System-Erweiterunen erhalten, nicht aber programmeigene Gadgets. Entsprechend wird das Gadget »zerstört«, wenn die Library aus dem Speicher entfernt wird. Das geht mit einem einfachen FreeClass() (s. »Listing 2«).
Der Dreh- und Angelpunkt eines jeden Objekts ist sein Dispatcher (zu deutsch etwa Nachrichtenverarbeiter). Egal ob Daten gesetzt werden sollen (OM_SET), Daten erfragt werden sollen (OM_GET) oder ein Refresh ausgelöst wird (IM_DRAW/GM_RENDER): Immer wird diese Funktion angesprungen. Die eigentliche Aktion wird als numerische Methoden-ID übergeben. Den grundsätzliche Dispatcher-Aufbau sehen Sie in »Listing 3«.
Sehr wichtig dabei: Der Aufruf der Basisklasse im Defaultzweig. Alle Aufgaben, die wir nicht erledigen (wollen), werden von der Basisklasse übernommen soweit wie möglich. Ist die Basisklasse ebenfalls von einer anderen Klasse abgeleitet, gibt auch diese die Nachricht eine Ebene weiter zurück, falls sie nicht verarbeitet werden konnte. Diese Schleife setzt sich fort bis zur Root-Klasse. Aber auch bei den selber behandelten Methoden ist es oft sinnvoll oder sogar notwendig, zuerst die Basisklasse aufzurufen.
Erstellen eines Gadgets
Je nachdem, welche Art von Gadget erstellt werden soll, ist zuerst zu überlegen, von welcher bestehenden Klasse das neue Gadget abgeleitet werden soll. Wird von der Root-Klasse abgeleitet, stehen nur die grundlegenden Funktionen bereit. Wird von höheren Gadgets abgeleitet, kann auf deren Funktionalität aufgesetzt werden und man kann sich viel Programmierung sparen. Wie gesagt, hängt es von der Basis ab, die vom neuen Gadget ab genutzt wird. Meist wird die GadgetClass zum Einsatz kommen, da diese alle Funktionen im Zusammenhang mit normalen Gadgets liefert (z.B. Normal/Selekt-Status usw.). In der Tabelle »Gadget-Klassen« finden Sie die vordefinierten Gadgets.
BOOL DisposeExampleGClass(Class *clas) { if(clas) if(!FreeClass(clas)) return( FALSE ); /* wenn Classe nicht freigegeben werden kann, */ /* muß die Library im Speicher bleiben */ return( TRUE ); } Listing2: Das Entfernen eines Gadgets. |
Lassen Sie sich vom Namen aber nicht täuschen! Es handelt sich lediglich um die interne Funktionalität, nicht um einen sichtbaren Button. Dazu müßte vom button.gadget abgeleitet werden. In der Regel ist GADGETCLASS die richtige Ausgangsbasis für die Gestaltung eigener Gadgets unter AmigaOS 3.5.
Auf bestehende Gadgets zurückgreifen
Die einfachste Möglichkeit besteht darin, auf bereits bestehende Gadgets zurückzugreifen und diese zu kombinieren oder zu erweitern. Nach außen ist dieses Gadget/diese Gruppe nur als einziges Gadget sichtbar. Auch alle Tagwerte werden für dieses Gadget gesetzt. Intern ist dann unsere Gadgetgruppe dafür verantwortlich, daß die Tags auch den richtigen »Empfänger« erreichen. Intern handelt es sich meist um eine Gruppe, da diese sowieso andere Objekte aufnehmen kann und uns somit die komplette Größenberechnung und Layouts abnimmt.
Achtung: Innerhalb der Reaction-Umgebung sollte vom layout.gadget als
Gruppe abgeleitet werden, da dieses die Größenberechnung erledigt! Die Behandlung
der Objektmethoden bezieht sich darauf, daß intern mehrere Objekte vorhanden
sind:
OM_NEW: Es müssen alle Unterobjekte erzeugt werden OM_DISPOSE: Es müssen
alle Unterobjekte freigegeben werden, sofern sie nicht Member (Mitglied) einer
anderen Gruppe sind und dadurch automatisch durch diese aus dem System gelöscht
werden. OM_SET: Daten setzen, eventuell an Unterobjekte weitermelden.
OM_GET: Daten zurückliefern, evtl. von Unterobjekten zu erfragen. Alle
anderen Methoden können meist direkt an die Basisklasse per DoSuperMethod()
weitergegeben werden.
Sinnvoll ist diese Vorgehensweise z.B. bei einem Telefonwählfeld. Für das Programm interessant ist lediglich die eingegebene Nummer. Ob diese nun direkt eingegeben wird (String-Gadget) oder per Tasten ist dem Programm egal. Auch ist es für das Programm einfacher, ein einzelnes Telefonwählfeld-Gadget zu erzeugen, als alle dreizehn Gadgets einzeln und die zugehörigen Layoutgruppen. Das genaue Vorgehen zeigt das Beispielprogramm »Phone-Field« (s. Bezugsquellen).
Eine Erweiterungsmöglichkeit besteht in einer zusätzlichen Klasse, die Telefonnummern verwaltet und in einer Liste zur Auswahl anbietet. Bei Auswahl könnten per interner GM_UPDATE-Methode die Daten direkt an das PhoneField-Gadget weitergegeben werden.
Übersicht der Methoden:
|
|
Die folgenden Methoden bilden das Grundgerüst (Rootclass) und beginnen mit dem Prefix "OM_" (Object Methode; zu finden in intuition/classusr.h): | |
OM_NEW | Es wird ein neues Objekt angelegt (läuft als erste Methode) und wird vom Anwendungsprogramm durch NewObject() ausgelöst. Mit den Werten aus der Tagliste sind die Objekt-Instanzdaten vorzuinitialisieren. Zurückzugeben ist die neue Klasse oder NULL im Fehlerfall. |
OM_DISPOSE | Objekt wird gelöscht (läuft als letzte Methode) und wird vom Anwendungsprogramm durch DisposeObject() ausgelöst. |
OM_SET | Es werden neue Daten in der Tagliste übergeben.Ein Returnwert von 1 besagt, daß ein Refresh des Gadgets notwendig ist (sonst 0). In wieweit ein automatischer Refresh erfolgt, bleibt dem Gadget überlassen. |
OM_GET | Es werden Daten des Objekts abgefragt. Wurden die Daten ermittelt, wird 1 zurückgeliefert, im Fehlerfall 0. |
OM_ADDMEMBER | Ein Objekt soll zur klasseneigenen Liste hinzugefügt werden (nur bei Gruppen-Objekten möglich) |
OM_REMMEMBER | Entfernt entsprechend ein Objekt aus der Liste. |
OM_UPDATE | Objekt soll sich aktualisieren (z.B. externe Datenänderung übernehmen). Zusätzlich wird das Gadget neu gezeichnet (Refresht). Diese Methode sollte nur gadgetintern benutzt werden! |
OM_NOTIFY | Damit können sich die Objekte untereinander über Veränderungen (z.B. Sliderposition) informieren (Gadget-Tags ICA_Target und ICA_Map). |
Bei der Erstellung von Gadgets kommen noch weitere interessante Methoden hinzu. Diese beginnen zur leichteren Erkennbarkeit mit einer GM-Gadget-Methode zu finden in intuition/gadgetclass.h>P>: | |
GM_HITTEST | Das Gadget soll prüfen, ob die Maus darüber gedrückt wurde. Rückgabewert ist GMR_GADGETHIT für ja und 0 für nein. |
GM_RENDER | Gadget soll sich neu zeichnen. Anhand des Redrawmoduses (Redraw/Toggle/Update) wird die Zeichnungsart unterschieden. |
GM_LAYOUT | Ist eine Layout-Anforderung. Existiert seit V39 und wird vom Reaction-Layoutgadget verwendet, um den Gadgets ihre Position und Größe zuzuweisen bzw. um bei Datatype-Objekten ihre Größe berechnen zu lassen. |
GM_GOACTIVATE | Wird vor dem Aktivieren des Gadgets aufgerufen. |
GM_GOINACTIVATE | Wird nach dem Verlassen des Gadgets aufgerufen. |
GM_HANDLEINPUT | Benutzereingaben sind zu verarbeiten (z.B. Mausbewegungen oder Tastendrücke bei Eingabeobjekten). |
Images, die von der Rootclass abgeleitet sind, besitzen ebenfalls zusätzliche Methoden, welche mit dem Prefix IM_ (Image Methode) gekennzeichnet sind (zu finden in intuition/imageclass.h): | |
IM_HITTEST | Das Image soll prüfen, ob die Maus darüber gedrückt wurde. Returnwert TRUE für ja, FALSE für nein. |
IM_DRAW | Image neu zeichnen (wird z.B. durch DrawImageState() ausgelöst). |
IM_ERASE | Löscht den Ausgabebereich des Images (wird z.B. durch EraseImage() ausgelöst). |
IM_MOVE | Löschen des Images und zeichnen an der neuen Position. |
IM_FRAMEBOX | Berechnet die Rahmendimensionen. |
IM_HITFRAME | Wie IM_HITTEST, allerdings unter Einbeziehung des Rahmenbereichs. |
IM_DRAWFRAME | Zeichnen des Images innerhalb dem definierten Bereich. |
IM_ERASEFRAME | Löschen des Images (Gegenstück zu IM_DRAWIMAGE). |
Eine einfache Zeichenfläche
|
Da das Gadget-Layout automatisch durch die Window-Klasse vorgenommen wird, besteht programmseitig keine Möglichkeit mehr, sich einen Bereich zu reservieren, indem z.B. direkt gezeichnet wird oder indem Ergebniswerte geprintet werden können. Läßt sich das Vorhaben nicht mehr mit einem der vorhandenen Standard-Gadgets lösen, so kann auf das DrawField-Gadget zurückgegriffen werden (zu finden in der gleichnamigen Schublade). Dieses nimmt lediglich Platz in Anspruch, entsprechend der Vorgaben in der Tagliste. Beim Refresh/ Zeichenanforderung wird eine Callback-Funktion im Programm angesprungen, die dann wieder die Fläche direkt füllen kann. Dadurch kann man darauf verzichten, ein komplett neues Gadget zu erzeugen. Beachten Sie hierzu auch den Abschnitt »Besondere Anforderung an Reaction-Gadgets«.
Ein komplettes Gadget
Der Schritt zu einem vollständigen Gadget liegt nur noch darin, die GM_RENDER-Methode selbständig auszuführen. Die anderen Aufgaben - Erstellen/Freigeben der Instanz, Setzen/Liefern von Werten - wurden bereits in den vorhergehenden Beispielen benutzt. Normalerweise vom Gadget zu unterstützen ist GM_HITTEST, um festzustellen, ob die Maus innerhalb dem Gadget geklickt wurde. Ist das der Fall, so muß GMR_GADGETHIT zurückgegeben werden, ansonsten 0. Die beiden Methoden GM_GOACTIVATE und GM_GOINACTIVATE wurden bereits oben beschrieben, zur Vollständigkeit fehlen nur noch die Return-Codes.
|
GM_GOINACTIVATE: Es ist kein Rückgabewert definiert.
GM_HANDLEINPUT:
GMR_MEACTIVE: Um das Gadget weiter aktiv zu lassen und auf weitere Input-Messages
zu warten.
GMR_NOREUSE: Um das Gadget zu verlassen/deaktivieren.
GMR_REUSE: Gadget deaktivieren und InputEvent weiterverarbeiten lassen.
GMR_NEXTACTIVE / GMR PREACTIVE: Um das nächste/vorherige Gadget zu aktivieren
(TabCycle).
Bei den Methoden GM_GOACTIVATE und GM_HANDLEINPUT kann GMR_VERIFY mit der Return-Wert mit oder verknüpft werden (bei GMR_NOREUSE), um eine IDCMP_GADGETDOWN-Nachricht an das Programm zu erzeugen.
Besondere Anforderung an Reaction-Gadget
Das erstellte Gadget ist bisher rein BOOPSI und kann auch so benutzt werden. Werden keine Funktionen aus höheren Libraries benutzt, so kann dieses Gadget bereits ab Kickstart 2.x (Library V37) benutzt werden! Damit es auch in der Reaction-Umgebung funktioniert, muß es noch die Methode GM_DOMAIN unterstützen, über welche die (minimalen, maximalen und nominalen) Größendaten des Gadgets abgefragt werden. Nur so paßt sich das Gadget in den automatischen Layoutprozess ein. In »Listing 4« finden Sie den Dispatcherauszug, der für alle drei Größenanfragen die selben Werte liefert, also keine Größenänderung des Gadgets zulässt.
Ein weiterer Sonderfall unter Reaction ist der Hintergrund. Ist beim normalen Intuition-Fenster in der Regel der Hintergrund immer Farbregister 0, so kann bei Reaction auch eine Hintergrundgrafik verwendet werden. Unterstützt das Gadget transparente Darstellung, ist vor dem Zeichen (bzw. Löschen) der Backfill-Hook zu installieren (REACTION_BackFill). Ein Beispiel sehen Sie in »Listing 5«.
Der letzte Punkt, der an die Reaction-Gadgets gestellt wird, ist eine Funktion zum Erfragen der Klassenbasis. Die Funktion muß den Einsprung-Offset -30 besitzen. Der Name ist zwar nur für den Benutzer von Interesse, dieser sollte aber in Angleichung an die anderen Funktionsnamen mit dem großgeschriebenen Classennamen + ¿_GetClass" lauten also hier z.B. EXAMPLEG_GetClass().
Intern ist die Funktion absolut simpel, da lediglich der Classenzeiger (aus der Library-Base) zurückgeliefert werden muß:
Gadget-Klassen | |
Definiert in intuition/classusr.h sind unter anderem: | |
ROOTCLASS | rootclass |
GADGETCLASS | gadgetclass |
GROUPCLASS | groupclass |
IMAGECLASS | imageclass |
BUTTONCLASS | buttonclass |
Auch wenn diese drei Punkte ausgeführt werden, ist das Gadget weiterhin voll BOOPSI-kompatibel und kann daher identisch in normalen Umgebungen sowie in Reaction-Umgebungen eingesetzt werden.
Nach der vielen Theorie liefern die Beispielcodes vermutlich mehr Informationen. Dazu sind sie wieder entsprechend mit Kommentaren versehen. Zu unterscheiden ist der eigentliche Gadget-Sourcecode (jeweils in den Unterschubladen gadgets zu finden) und der Sourcecode des Anwendungsprogramms (»Beispielanwendung.c«). Beide sind voneinander getrennt zu übersetzen. Dabei wird aus dem Gadget-Source eine Library mit der Endung .gadget erzeugt, die nicht direkt gestartet werden kann, sondern sich nur durch andere Programme benutzt läßt. In »Listing 6« finden Sie ein einfaches Benutzungsgerüst.
Die vollständigen Beispielsourcen sind in der Schublade »ExampleG« zu finden. Es handelt sich um eine Ableitung vom Button-Gadget, wobei selber nichts verarbeitet wird, sondern alles an die Basisklasse weitergereicht wird. Er eignet sich daher gut als Ausgangsbasis für eigene Gadgets und Versuche!
Erstellen eines Images
Images funktionieren genauso wie die Gadgets; mit dem kleinen Unterschied, daß im Dispatcher nur Methoden vom Typ OM_xxx und IM_xxx auftreten können. Images alleine sind nicht interaktiv, d.h. sie können nicht angeklickt oder verändert werden. Diese Aufgaben übernehmen die Gadgets, welche aber auf Images zurückgreifen können, um die Daten darzustellen. Bestes Anwendungsbeispiel ist der Button. Alleine stellt dieser nur den äußeren Rahmen und eventuell einen Textinhalt dar und reagiert auf das Anklicken. In Kombination mit einem Penmap- oder Bitmap-Image, kann der Button auch Grafiken als Schaltfläche benutzen.
Von der Programmierung her verhalten sich Gadget und Image identisch. Beide werden über den Dispatcher bedient, lediglich die Methoden sind abweichend. Und natürlich enden die (Library) Namen mit .image und sind in der Systemschublade classes/images zu finden. Anhand des led.image soll hier ein kurzer Überblick gegeben werden.
struct Hook *oldhook; if(egd->egd_Hook) oldhook = InstallLayerHook( gpr->gpr_GInfo->gi_Layer,egd->egd_Hook); /* ... zeichnen ... */ if(egd->egd_Hook) InstallLayerHook( gpr->gpr_GInfo->gi_Layer,oldhook); Listing 5: Einen Hindergrund verwenden |
Wie bei den Gadgets auch, werden beim Laden die benötigten Libraries geöffnet. In der Open-Funktion wird die Image-Klasse erzeugt und der Benutzungs-counter hochgezählt.
Ebenso wird in der Close-Funktion die Klasse freigegeben und der Counter reduziert. Das led.image unterstützt lediglich die vier Methoden:
OM_NEW: wenn ein neues Image erzeugt wird.
OM_SET / OM_UPDATE: zum Setzen/Aktualisieren der Werte,
OM_DRAW: zum Zeichnen des Images. Alle anderen Aufgaben werden direkt an die
Basisklasse (imageclass) weitergereicht.
Anwendungsseitig kann das Image z.B. mit einem Button verknüpft oder alleine dargestellt werden. Es paßt sich dabei wieder automatisch dem Layout an, wenn es innerhalb einer Reaction-Umgebung benutzt wird (Methode IM_DOMAIN muß behandelt werden). Als dritte Möglichkeit kann die led.image-Klasse erzeugt werden (per NewObject()) und mit Hilfe DrawImage State() aus der intuition. library dargestellt werden. Dabei muß beim Erstellen eine Größe für das Image vorgegeben werden (IA_Width/ IA_Height).
Diese Möglichkeit wird auch im Beispielprogramm »test.c« (Verzeichnis led_ic) verwendet:
1. Image-Classe öffnen
2. Fenster öffnen
3. led.image erzeugen
4. Image anzeigen
5. warten, bis das Fenster geschlossen wird
6. Image freigeben
7. Image-Classe schließen Ergänzend habe ich ein weiteres Beispiel beigelegt
(»Beispielanwendung.c«), daß das Led-Image zur Realisierung einer Digital-Uhr
verwendet. Dabei kommt ein Größen-änderbares Fenster zum Einsatz.
Einbindung in ReActor
Die neu erstellen Gadgets/Images können Sie direkt vom Programm aus benutzen, indem die entsprechende Gadget/Image-Klasse angefordert wird. Soll aber die Oberfläche des Programms auch weiterhin komfortabel mit ReActor erstellt werden, so sind die neuen Gadgets/Images in dieses Tool zu integrieren. Das ist aber nicht schwer und schnell erledigt !
Im Verzeichnis von ReActor gibt es das Unterverzeichnis profiles und dort die weiteren Unterschubladen für gadgets und images (und weitere, hier aber nicht benötigte Schubladen). Wie zu vermuten ist, befinden sich in der Gadget-Schublade die Beschreibungsdateien für die Gadget (und Gruppenobjekte), in der anderen entsprechend für die Images. Hier muß eine neue Datei erstellt werden, in der die Möglichkeiten des neuen Gadgets/Images beschrieben wird. Die Datei ist sehr übersichtlich aufgebaut und liegt im Klartext vor (ASCII-Format). Sie beginnt in der ersten Zeile mit dem Namen des Gadgets. Darunter folgt der Name, der in der ReActor-Auswahlliste angezeigt wird. Als nächste Zeile ist der vollständige Pfad und Dateiname anzugeben, über das das Gadget geladen werden kann.
Per INCLUDE können dann noch andere Beschreibungsdateien eingebunden werden. So spart man sich Tiparbeit, wenn das neue Gadget Tags anderer Gadgets mitbenutzt (bei Ableitungen oder z.B. die allgemeinen Gadget-Tags). Darunter sind dann die einzelnen Tags anzugeben, die das Gadget kennt. Abgeschlossen wird diese Liste (und die Datei) mit dem Schlüsselwort END. Es folgt eine kurze Beschreibung, wie die Tags anzugeben sind. Ausführliche Informationen finden Sie in der Anleitung zu ReActor.
Gegliedert ist die Zeile von links nach rechts, beginnend mit der Tagart BOOLEAN (Ja/Nein), STRING (Text), INTEGER (Zahlenwert), IMAGE (Grafik),
PEN (Farbstift), SELECT (Auswahlliste), FLAGS (Mehrfachauswahl), PRECENT (prozentualer Wert 0 bis 100 Prozent); es existieren noch viele weitere Arten.
Danach folgt zuerst der Zahlenwert des Tags, dann seine Einsatzmöglichkeiten:
struct ExampleGBase *ExampleGBase; if((ExampleGBase = (struct ExampleGBase *) OpenLibrary("gadgets/ExampleG.gadget",44))) { printf("ExampleG LibBase: 0x%lx, Gadget-Class : 0x%lx\n" ,ExampleGBase,EXAMPLEG_GetClass()); /* ... Gadget kann benutzt werden ... */ /* erzeugen mit: gb_ExampleGadget = NewObject( EXAMPLEG_GetClass(),NULL,<tags>); */ /* einfügen in ein Fenster: AddGList(gb_Window,gb_ExampleGadget,-1,1,NULL); */ /* entfernen aus dem Fenster mit: RemoveGList(gb_Window,gb_ExampleGadget,1); */ /* löschen mit: DisposeObject(gb_ExampleGadget); */ CloseLibrary((struct Library *)ExampleGBase); } else printf("ERROR: can`t open ExampleG.gadget V44.\n"); Listing 6: Ein einfaches Beispiel-Gerüst zur Gadget- Programmierung |
Danach folgen nur noch Tagartspezifische Zusatzangaben, z.B. die Einträge für die Auswahlliste. Am einfachsten ist es, eine bestehende Beschreibungsdatei zu kopieren und einfach abgeändert unter dem neuen Namen zu speichern.
Wenn Sie nun ReActor starten, sind Ihre neuen Gadgets/Images automatisch in der Auswahlliste und können wie gewohnt in die Oberfläche integriert werden. Auch in der Vorschau stehen sie sofort zur Verfügung. Wenn Sie ein öffentliches Gadget/Image erstellen, vergessen Sie nicht, auch die entsprechende Beschreibungsdatei mitzuliefern.
Es ist zu hoffen, daß diesem Grundgerüst viele weitere (programmspezifische) Gadgets folgen (ähnlich MUI). Je mehr unterschiedliche Gadgets existieren, umso höher ist die Wahrscheinlichkeit, daß beim Erstellen eines neuen Programms bereits alle Elemente zur Verfügung stehen und so die Erstellung neuer Programme in kürzerer Zeit erfolgen kann.
Bei Fragen zur Programmierung können Sie sich gerne per E-Mail an den Autor
des Artikels wenden: michael@meicky-soft.de
Alle Programmarchive sind wieder auf der CD zum Heft zu finden sowie auf der
Homepage des Autors:
http://www.meicky-soft.de/amiga-magazin/reaction.html
Damit sind wir am Ende unseres Kurses.
Kommentare, Fragen, Korrekturen und Kritik bitte an Webmaster
AMIGA schicken.
Zuletzt aktualisiert am 03. März 2000, Michael Christoph.