Im dritten und letzten Kursteil der
p.OS-Programmierung werden wir das Kapitel
Intuition unter p.OS mit den Men�s und dem
EasyRequester abschlie�en. Zum besseren
Verst�ndnis werden wir nat�rlich unser
Beispielprogramm aus den vorangegangenen Teilen
wieder erweitern. Es wird dann kein Problem mehr
f�r Sie sein, Programme unter p.OS zu entwickeln.
Da Ihnen p.OS die meisten Aufgaben beim Erstellen der Oberfl�che abnimmt (Fontsensitiv, Men�layout, Gadgetpositionierung, Windowresizing, ...), k�nnen Sie sich ganz der Implementierung der gew�nschten Aufgaben widmen. Unser Beispielprogramm wird Sie dabei zus�tzlich unterst�tzen, indem Sie ben�tigte Programmteile (Gadgets/ Men�s/Messageloop/...) einfach per Cut-Copy-Paste �bernehmen.
Beachten Sie dabei aber stets, da� f�r alle verwendeten Funktionen die entsprechenden Betriebsystem-Libraries und -Devices ge�ffnet sein m�ssen. Diese sind am Programmende dann wieder alle zu schlie�en. Beachten Sie auch, da� im Fehlerfall ein kontrollierter Programmabbruch stattfinden mu�, bei dem alle reservieren Resourcen wieder freizugeben sind. Im Fehlerfall mu� auch immer eine Mitteilung an den Benutzer erfolgen (z.B. per pOS_ PrintDosErr() oder pOS_ SPrintf()). Auch bei einem Workbenchstart unter p.OS d�rfen Sie die pDOS-Ausgabefunktionen benutzen.
Im Bedarfsfall wird ein Console-Fenster zur Ausgabe
ge�ffnet. Bei Oberfl�chen-Programmen empfiehlt es
sich aber, den Fehler �ber Requester (z.B.
pOS_EasyRequest Args()) anzuzeigen. Die
Fehlertexte sollten dabei f�r jederman
verst�ndlich und ausf�hrlich sein. Statt �Lock
failed� verwenden Sie besser �Datei %s ist nicht
zu finden.�.
Dabei sollte auch der (vollst�ndige)
Dateiname angegeben werden. Falls Sie zus�tzliche
Informationen bei einer Fehlermeldung w�nschen,
k�nnen Sie z.B. einen programmspezifischen
Fehlercode in Klammern mit ausgeben lassen.
Beachten Sie, da� im Fehlerfall unerfahrene
Benutzer meist nur den halben Fehlertext, ohne
weitere Angaben, wiedergeben k�nnen. Erfahrene
User werden bei ausf�hrlichen Fehlertexten den
Fehler meist selbst�ndig beheben.
Auf die ANSI-Funktionen exit()/atexit()/abort() mu� im
Fehlerfall unbedingt verzichtet werden, da diese
intern auf Amiga-Funktionen zur�ckgreifen, was
unweigerlich zu einem Programmfehler f�hrt. In
Zukunft wird Ihnen daf�r die Funktion
pOS_ExitProcess() zur Verf�gung stehen. Es ist
aber immer besser, wenn die Programme (und auch
die Funktionen) nur einen Ausstiegspunkt (eine
Return-Anweisung) enthalten und dadurch auf
harten Programmausstieg verzichten. Jedes
Programm (zumindest bei strukturierten
Programmiersprachen wie C oder C++) l��t sich so
entwickeln, da� diese Bedingung zutrifft. C++
(Version 3) bietet hierzu auch das
Exception-Handling an.
Damit ist es sehr einfach,
aus jeder tiefen Unterfunktion wieder zu einem
kontrollierbaren Punkt zur�ckzukehren. Nach
M�glichkeit sollte das Programm nach der
Fehlermeldung (evtl. auf Benutzerwunsch)
weiterlaufen.
Programmprojekt unter p.OS: Unser selbstgestaltetes Fenster hat noch ein Men� bekommen |
- DOSFAIL_OK (0) : Programm wurde fehlerlos abgearbeitet - DOSFAIL_WARN (5) : Warnung, z.B. bei fehlerhaften Parametern - DOSFAIL_ABORT (8) : Benutzerabbruch durch CTRL-C - DOSFAIL_ERROR (10) : einfacher Fehler - DOSFAIL_FAIL (20) : gro�er Fehler, z.B. Speichermangel
Der zweite Punkt, der nur wenigen Anwendern auffallen
wird, ist, da� das Window w�hrend der Men�auswahl
nicht mehr gesperrt ist. Dadurch entf�llt eine
m�gliche Deadlock-Situation, wie sie beim Amiga
auftreten k�nnte.
Die Men�struktur wird, �hnlich
den Gadgets, nur beschrieben. Die Men�anordnung
und Positionierung �bernimmt das OS wieder
vollst�ndig f�r Sie. Die Men�eintr�ge sind
wiederum Objekte, wodurch auch Grafiken und
Animationen als Eintr�ge kein Problem sind. Die
Men�struktur finden Sie in �p:pIntui/Menu.h�.
Interessant sind hierbei mt_Type f�r
Title/Item/Sub, mt_Lable f�r den Texteintrag und
mt_CommKey f�r einen Shortkey. Seltener ben�tigt
werden mt_Flags (z.B. zum Abhaken) und
mt_MutualExclude (f�r Ausschlu�punkte). Die
angesprochenen Grafiken und Animationen bekommen
Sie ins Men� �ber eine IntuiObj-Beschreibung in
mt_Tags. Das Ende der Men�beschreibung wird per
mt_Type MENUTAGTYP_End abgeschlossen.
|
Mit MENUITF_Toggle wird bei jeder
Auswahl der Hakenzustand gewechselt. Ob ein Punkt
aktiviert ist, k�nnen Sie beim Start �ber
MENUTIF_ IsChecked festlegen. Die W�hlbarkeit
definiert man �ber MENUITF_Disabled (gesetzt =
nicht w�hlbar).
Einer Erkl�rung bedarf noch der
Eintrag f�r mt_MutualExclude. Die Funktionsweise
ist �hnlich den MX-Gadgets. Bei der Auswahl eines
Men�punktes bestimmt die Maske in
mt_MutualExclude, welche anderen Men�punkte
auszuschalten sind.
Es lassen sich nur die
Eintr�ge der aktuellen Men�ebene beeinflussen.
Dabei werden maximal die ersten 32 Eintr�ge
beeinflu�t (32 Bits im ULONG). Besser
verdeutlichen l��t sich das an einem Beispiel,
etwa die Style-Auswahl f�r eine Schrift. Hierbei
kann entweder Plain oder eine Kombination aus
Bold, Italic und Underline auftreten. Dabei ist
bei der Auswahl von Plain immer dieser Punkt
abzuhaken, alle anderen mu� man deaktivieren. Die
anderen drei Punkte k�nnen einzeln ein- und
ausgeschaltet werden. Aus dieser Anforderung
ergibt sich folgende Men�beschreibung:
mt_Lable = "Plain" mt_Flags = MENUITF_Hook | MENUITF_IsChecked mt_MutualExclude = 0x0E /* %00001110 => B/I/U ausschalten */ mt_Lable = "Bold" mt_Flags = MENUITF_Hook | MENUITF_Toggle mt_MutualExclude = 0x01 /* %00000001 => Plain aus */ mt_Lable = "Italic" mt_Flags = MENUITF_Hook | MENUITF_Toggle mt_MutualExclude = 0x01 /* %00000001 => Plain aus */ mt_Lable = "Underline" mt_Flags = MENUITF_Hook | MENUITF_Toggle mt_MutualExclude = 0x01 /* %00000001 => Plain aus */
Der Eintrag Plain ist beim Start abgehakt und besitzt kein Toggle-Flag, um diesen Punkt bei mehrfacher Auswahl von Plain nicht zu deaktiveren, wodurch kein Punkt mehr aktiv w�re. Es gibt aber trotzdem eine Situation, die das OS nicht abfangen kann. W�hlen Sie z.B. Bold, wird der Punkt abgehakt und Plain deaktiviert. Bei der zweiten Auswahl von Bold wird der Punkt wieder deaktivert und keiner der vier Punkte ist mehr gesetzt. Diesen Fall m�ssen Sie zwangsl�ufig selbst im Messageloop abfangen (vereinfachte Darstellung):
if( pOS_GetWindowMenuChecker(0)==FALSE && pOS_GetWindowMenuChecker(1)==FALSE && pOS_GetWindowMenuChecker(2)==FALSE && pOS_GetWindowMenuChecker(3)==FALSE) pOS_SetWindowMenuChecker(0,TRUE);
Einfacher w�re die Aufgabe, wenn ein Punkt immer alle anderen ausschlie�en w�rde: In diesem Fall geben Sie f�r jeden Punkt nur das Hook-Flag an. Dadurch wird bei doppelter Auswahl desselben Punktes kein Toggle durchgef�hrt und der Punkt bleibt weiterhin angew�hlt. Die vier MutualExclude-Eintr�ge lauten dann:
0x0E /* %00001110 */ 0x0D /* %00001101 */ 0x0B /* %00001011 */ 0x07 /* %00000111 */
Die Maske
l��t sich, wie bereits erw�hnt, auf die ersten 32
Men�eintr�ge ausdehnen. Beachten Sie, da�
Trennlinien auch einen Eintrag darstellen, der
nicht beeinflu�bar ist und daher in der Maske
durch eine 0 angezeigt werden sollte.
Die MX-Gadgets arbeiten intern nach demselben Schema.
Allerdings ist hier die �nur einer
aktiv�-Schaltung vorgegeben. Ein anderes
Verhalten k�nnen Sie �ber ICLTAG_ MutualExclude
als Maske �bergeben.
Zur Laufzeit kann der
Aktivierungszustand/W�hlbarkeit �ber
pOS_MenuItem->mi_ Flags ermittelt werden. Zum
�ndern existieren die Funktionen
pOS_SetWindowMenuChecker() und
pOS_EnableWindowMenu(). Die dabei ben�tigte
pOS_MenuNum setzen Sie wie folgt zusammen:
Entweder tragen Sie den Wert als ULONG oder die
drei Einzelkomponenten als UBYTEs ein. Die Punkte
werden jeweils ab 0 gez�hlt und k�nnen
theoretisch bis maximal 254 laufen. Die Zahl 255
(= 0xFF) hat eine Sonderstellung und bedeutet,
da� dieser Eintrag nicht beachtet werden soll
(wenn beispielsweise kein Sub-Men� existiert).
Die Men�nummern f�r das zweite Men�, dritter Eintrag (kein Sub) w�rde sich somit aus
pOS_MenuNum->men_U.men_Pck[MENNUPCK_Title] = 1 pOS_MenuNum->men_U.men_Pck[MENNUPCK_Item] = 2 pOS_MenuNum->men_U.men_Pck[MENNUPCK_Sub] = 0xFF
oder aus
pOS_MenuNum->men_U.men_Num = 0x0102FF00
zusammensetzen. �ber diese Men�nummern k�nnen Sie auch die Adresse des Men�eintrags per pOS_GetMenuItemFromNum() ermitteln. �ber pOS_CreateMenuTagA() erzeugen Sie aus der Men�beschreibung die interne Men�struktur, die noch �ber pOS_PreLayoutMenu() vorbereitet werden mu�. Danach kann sie bei Bedarf per pOS_SetMenuStrip() in das zugeh�rige Fenster eingeh�ngt werden. Verwenden Sie mehrere Fenster, sollte das Men� in jedem Fenster verf�gbar sein. Dabei d�rfen Sie den einen Men�zeiger in mehreren Fenstern verwenden. Am Programmende ist die interne Men�struktur mit pOS_DeleteMenu() freizugeben.
Nach der Men�auswahl sendet
Intuition eine IDCMP_ MenuPick-Message. Dabei ist
9 im_Code-Feld die gew�hlte Men�nummer vermerkt.
Die Men�verteilung kann wieder mit einer
verschachtelten Switch-Case-Konstellation
ausgewertet werden. Bedenken Sie, da� der erste
Eintrag immer 0 lautet. Alternativ k�nnen Sie
statt der Zahlen auch auf Defines oder
Enumerations zur�ckgreifen, um auch nach
Men�umbauten keine gro�en �nderungen im
Messagelloop durchf�hren zu m�ssen. Eine andere
M�glichkeit ist, im User-Zeiger des Men�s eine
Funktions-Adresse abzulegen, die man nur noch
aufrufen mu�.
Das p.OS-StyleGuide schreibt vor,
da� Men�punkt-Shortcuts, im Gegensatz zu Gadgets,
nicht lokalisiert werden. Die g�ngigen Punkte und
Shortcuts lauten somit:
Bei Auswahl eines
�Jahreszeiten�-Men�eintrages wird die Wahl, wie
bereits bei den Gadgets besprochen, �ber die
zentrale Funktion SetDatas() f�r alle Gadgets
aktiviert. Neu in dieser Funktion ist, da� die
aktuelle Auswahl �ber pOS_ SetWindowMenuChecker
auch im Men� gesetzt wird.
Bei der Auswahl von
�Quit� wird, wie nicht anders zu erwarten, das
Programm beendet. Dabei k�nnte z.B. noch eine
Abfrage eingebaut werden, ob das Programm
wirklich beendet oder ob evtl. ver�nderte Daten
noch gespeichert werden sollen.
Project-Men� | weitere Men�s | Edit-Men� | |||
New | Neu (N) | Help | Hilfe (?) | Cut | Ausschneiden (X) |
Open | Laden (O) | Copy | Kopieren (C) | ||
Save | Speichern (S) | Paste | Einf�gen (V) | ||
Save As | Speichern unter (A) | Delete | L�schen | ||
Drucken (P) | Undo | Zur�cknehmen (Z) | |||
Info | Information | Redo | Wiederherstellen | ||
Quit | Beenden (Q) |
Die normalen Requester haben aber einen Nachteil � sie arbeiten synchron. Die Funktion �pOS_EasyRequestArgs()� kehrt erst dann zur�ck, wenn der Benutzer ein Gadget aus dem Requester anklickt, bzw. (optional) eine Nachricht entsprechend der gesetzten IDCMP-Flags aufgetreten ist. W�hrend dieser Zeit kann Ihr Programm auch nicht auf Refresh-Anforderungen durch das OS reagieren. Hierbei zeigt sich aber der Vorteil, wenn das Fenster nur Gadgets enth�lt (z.B. auch f�r normale Textausgaben). Solche Gadgets k�nnen sich n�mlich unabh�ngig vom Programm selbst�ndig neu zeichnen und aufbauen.
Sollten Sie aber dennoch in die Situation kommen, da� w�hrend der Requesterausgabe das Programm weiterlaufen bzw. auf andere Nachrichten reagiert werden soll, existieren hierf�r drei Funktionen. Mit �pOS_CreateRequestWin()� erzeugen Sie das Fenster identisch wie bei synchronen Requestern. Dabei erhalten Sie einen pOS_Window-Zeiger, den Sie zum Schlie�en des Requesters an �pOS_DeleteRequestWin()� �bergeben m�ssen.
Einen normaler Messageloop k�nnte folgenderma�en aussehen:
ULONG sigs=pOS_WaitSignal( (1L < window->win_UserPort->mp_SigBit) | (1L < requester->win_UserPort->mp_SigBit) | DOSSIGF_CTRL_C);
Eine h�ufige Anwendung k�nnte aber auch sein, da� der EasyRequester nur einen Abbruch-Schalter enth�lt, mit der sich die aktuelle Berechnung durch das Programm vorzeitig beenden l��t. Dann m�ssen Sie regelm��ig mit �pOS_RequestWinHandler()� den Zustand des Requesters abfragen. Die Funktion erzeugt folgende Returnwerte:
2: es liegt keine
Nachricht vor (nur wenn Handler-Wait auf FALSE
gesetzt wurde)
1: ein gesetztes IDCMP-Ereignis
ist eingetreten
0: Schalter ganz rechts (meist
Abbruch) wurde angeklickt (bzw. einziger
vorhandener)
gr��er 0: Schalterposition
fortlaufend von links ab 1 gez�hlt
Beachten Sie,
da� das Schlie�en des Requesters nicht
automatisch geschieht, sondern mit
�pOS_DeleteRequestWin()� erledigt werden mu�.
Wollen Sie den Requester mit einer
Fortschrittsanzeige versehen, finden Sie das
entsprechende Gadget �ObjATool_ProcessGadA.class�
in der �ObjATool.library�.
Damit haben wir alle Komponenten f�r ein vollst�ndiges GUI-Programm zusammen: Windows, Gadgets, Men�s sowie deren Erzeugung und Auswertung. Der letzte Schritt sollte das Lokalisieren des Programms sein. Dabei wird das Amiga-kompatible Catalog-Konzept verwendet. Eine Catalog-Datei �ffnen Sie mit pOS_OpenCatalog() und schlie�en Sie am Programmende mit pOS_CloseCatalog(). Zur Laufzeit k�nnen Sie die Texte per pOS_GetCatalogStr() abfragen. Als letzten Parameter erwartet die Funktion einen Default-String, der zur�ckgegeben wird, wenn der Catalog nicht ge�ffnet werden konnte, bzw. wenn der String im Catalog fehlt. Vor oder nach Nutzung der Funktionen m�ssen Sie nat�rlich die �pLocale.library� �ffnen und schlie�en.
Die erste Aktion des Programms sollte das �ffnen der pLocale.library und des Catalogs sein. Dadurch kann auch die Template-Erkl�rung landesspezifisch erfolgen. F�r das Template sowie die im Programm fest eingebaute Sprache, empfehlen wir Englisch. Vor allem im Public Domain-Bereich kann durch die Catalog-Dateien eine gro�e (sprachenunabh�ngige) Verbreitung erfolgen. Es findet sich immer jemand, der f�r eine fehlende Sprache die Cataloge erg�nzt und somit das Programm noch mehr Benutzern zug�nglich macht. Dabei sollte man aber auch immer die Anleitungsdatei mit �bersetzen.
Auf die Lokalisierung eines Programms werden wir aber erst in lose folgenden, k�nftigen Kursteilen eingehen. Die Entwicklerunterlagen enthalten neben den Autodocs zu allen Libraries/Devices/Objekten auch jede Menge Beispielprogramme, die auf einzelne Funktionen eingehen. Bei weiteren Fragen k�nnen Sie sich direkt per E-Mail (�develop@ prodad.de�) an proDAD wenden. Mittlerweile existiert f�r p.OS auch eine Mailing-List, in der Sie als registrierter Entwickler Fragen und Erfahrungen weitergeben k�nnen.
� Copyright by MagnaMedia Verlag AG, Haar bei M�nchen
Ver�ffentlichung und Vervielf�ltigung nur mit schriftlicher Genehmigung des Verlags