home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / spezial / 22 / doku.txt next >
Encoding:
Text File  |  1991-02-28  |  38.8 KB  |  755 lines

  1.                  Dokumentation zur "OOP-Spezial"
  2.                  -------------------------------
  3.  
  4. Eine  Übersicht  über  alle  Objekte  dieser  "Spezial"  sowie den
  5. vollständigen Namen  der  Unit,  in  der  sie  implementiert sind,
  6. bietet  "HIERARCH.DOC".  Hier   soll  vor  allem   auf  die  Frage
  7. eingegangen werden, warum und wie  die Hierarchie gemacht ist. Wie
  8. die Objekte implementiert  sind, wie  sie einzelne Detailprobleme,
  9. möge man bitte  dem jeweiligen Quellcode  entnehmen. Die Anwendung
  10. eines Objekts demonstriert entweder  ein Demoprogramm, das sich im
  11. gleichen Verzeichnis oder in  einem Unterverzeichnis mit dem Namen
  12. "DEMOS" findet,  oder  ein anderes  Objekt,  das von  ihm Gebrauch
  13. macht.
  14.  
  15. Diese  Spezial  stellt   Objekte  zur  Verfügung,   die  sich  der
  16. Programmierung von Oberflächenelementen auseinandersetzen. Zentral
  17. dafür ist wohl das Eventhandling (in der Unit "MouKey"). Hier kann
  18. sich ein  genaues  Studium  (auch  des  Quellcodes)  lohnen. Besitzer
  19. von Turbo Pascal 6.0 werden hier  nicht viel neues, nur ganz anders
  20. aufgebautes finden. Diese Spezial ist vor dem Erscheinen von Turbo
  21. Pascal  6.0  noch   unter  dessen   Vorgänger  entwickelt  worden.
  22. Allerdings  liegen  hier  die   Quellcodes  vollständig  bei,  und
  23. vielleicht  findet  man  bei  ihrem  Studium  oder  auch  bei  der
  24. Auseinandersetzung mit der Hierarchie, die in dieser Dokumentation
  25. diskutiert werden soll, Anstöße und Anregungen.
  26.  
  27. Die Dokumentation ist nach  Units geordnet, in welchem Verzeichnis
  28. sie sich befinden, verrät "HIERARCH.DOC".
  29.  
  30.  
  31.                              1. UBase
  32.                              --------
  33.  
  34. "Base" soll als Grundlage für  alle anderen Objekte der Hierarchie
  35. dienen, alle Objekte auf einen gemeinsamen Nenner zurückführen und
  36. somit  "kompatibel"   machen.  Da die Unit für  Listen-   oder  auch
  37. Arrayverwaltung gebraucht  werden soll,  muß sie  einen Destruktor
  38. enthalten, der den Speicher  freigibt, der von  und für das Objekt
  39. benötigt wird. Daher muß der Destruktor virtuell sein, damit auch
  40. immer der zum jeweiligen Objekttyp gehörige aufgerufen wird.
  41.  
  42. Alle Objekte  werden von  "Base" abgeleitet,  nicht nur scheinbare
  43. "Datenobjekte" wie z.B.  "SAAItem". Das hat  den Vorteil, daß man
  44. zweidimensionale, einfach  oder doppelt verkettete Listen
  45. sehr leicht herstellen  kann: Eine Liste,  deren Einträge wiederum
  46. Listen sind.  Das  ist  aber nur  möglich,  weil  das Listenobjekt
  47. selbst auch von Base abgeleitet wurde. Sonst hätte es nicht in die
  48. Liste eingetragen werden können.
  49. Sehr einfach können  so Sachen programmiert  werden, die gar nicht
  50. vorgesehen waren. Müssen sie auch nicht, da der Polymorphismus und
  51. die Vererbung in Fällen wie dem obigen Beispiel das ihrige tun.
  52.  
  53. Manchmal   will   man,    wie   z.B.    in   "AbstractList"   eine
  54. Reimplementation von  Methoden erzwingen.  Damit dabei  auch keine
  55. vergessen wird, kann die Methode  "Abstract" aus der Unit "UBase".
  56. Als Parameter  soll  ihr der  Name  des Objekts  übergeben werden,
  57. dessen  Methode  "Abstract"   aufgerufen  hat.   Sie  gibt  diesen
  58. Objektnamen  aus  und   erzeugt  einen   "Runtime-Error",  um  den
  59. Programmierer  (hoffentlich   noch   in  der   Testphase!)  darauf
  60. aufmerksam zu machen.
  61.  
  62.  
  63.                             2. UMouse
  64.                             ---------
  65.  
  66. "MouseObj" dient in der vorliegenden Version nur als Grundlage für
  67. spätere   Mausobjekte.    Die   meisten    Methoden   werden   von
  68. "EventHandlerObj" benötigt  und  sind deshalb  implementiert. Hier
  69. gibt  es  kein   großes  "Warum"  zu   beantworten:  Die  Maus  ist
  70. physikalisch gegeben, mitsamt all  ihren Fähigkeiten. Die Methoden
  71. des Mausobjekts  dienen  nur  zur  Abfrage  der  Mausposition, zum
  72. Setzen der  Position oder  zum Ändern  des Mauscursors. "MouseObj"
  73. stellt also nur  ein (hier  noch vereinfachtes)  Modell der realen
  74. "Maus" dar; die Methoden spiegeln  die Fähigkeiten der Maus wieder,
  75. die  Daten  von   MouseObj  speichern   ihren  Zustand  (sichtbar,
  76. Position, Knöpfe gedrückt oder nicht...).
  77.  
  78. Es macht keinen  Sinn, mehr  als eine Instanz  des Mausobjekts in
  79. einem Programm zu verwenden: Schließlich ist physikalisch auch nur
  80. eine Maus vorhanden. Deshalb sind die Konstanten "DoubleClickTime"
  81. und  "MouseDelay"   auch   modul-global  definiert;   sie  sollten
  82. innerhalb eines  Programmes  immer die  gleichen  Werte aufweisen,
  83. sind aber  als  typisierte Konstanten  gehalten,  damit Änderungen
  84. möglich sind.
  85.  
  86. Damit einem  Programm die  automatisch angelegte  Instanz "Mouse"
  87. des Typs "MouseObj" zur Verfügung steht, muß es die Unit "MouKey"
  88. laden; ansonsten muß  man sich  selbst um eine  Instanz des Typs
  89. "MouseObj" kümmern. Demonstriert wird  der Gebrauch von "Mouse" in
  90. "MKDemo".
  91.  
  92. "Mouse" müßte eigentlich  nicht von "Base"  abgeleitet werden, da
  93. es keinen  Sinn macht,  Mausobjekte in  einer Liste  zu verwalten.
  94. Aber man kann  nie wissen, wie  "MouseObj" einmal erweitert werden
  95. soll;  also  dient  es  der  Offenheit.  Außerdem wird  die
  96. Hierarchie dadurch  einheitlicher.  Ein anderer  Vorteil,  den man
  97. manchmal ausnutzen  möchte,  ist,  daß durch  die  Einführung von
  98. "Base" alle  von ihm  abgeleiteten Objekte  etwas gemeinsam haben:
  99. Der Offset-Zeiger auf die  VMT (virtuelle Methodentabelle) ist vor
  100. allen Variablen eines Objekts gespeichert.
  101.  
  102.  
  103.                             3. MouKey
  104.                             ---------
  105.  
  106. Hier dreht  sich  alles  um die  Verarbeitung  von hereinkommenden
  107. Ereignissen.   Das    eigentliche    Objekt   dieser    Unit   ist
  108. "EventHandlerObj",  das  die   Ereignisse  in  zwei  "EventQueue"-
  109. Objekten  verwaltet.  Eine  dieser  "Warteschlangen"  ist  für die
  110. Tastaturevents, die andere  für Mausevents  reserviert. Damit wird
  111. verhindert,  dass   Maus-  und   Tastaturevents  sich  gegenseitig
  112. durcheinander bringen können.  Das wäre der  Fall, wenn gerade ein
  113. Mausevent   bearbeitet   würde   und   durch   ein   Tastaturevent
  114. unterbrochen wird. Dann  würde zuerst  das in  die Queue eingefügt
  115. und danach wieder mit der Abarbeitung des Mausevents fortgefahren.
  116. Inzwischen wäre aber die Queue verändert und das Chaos perfekt.
  117.  
  118. Eine "EventQueue"  enthält  neben  zwei  Indexzeigern  ein Array
  119. reiner Datenobjekte vom Typ  "EventObj", der ein Event beschreibt.
  120. Dazu sind  der Zeitpunkt  und der  Typ des  Events nötig.  Je nach
  121. "EventType" sind spezifische Daten für die Beschreibung des Events
  122. von Bedeutung  (siehe  Listing). So  ist  bei einem  Mausevent die
  123. Position des Mauscursors und die  Anzahl der gedrückten Knöpfe von
  124. Interesse, bei  einem  Tastaturevent  muß  zwischen verschiedenen
  125. Arten unterschieden werden.
  126.  
  127. Daß diese  Objekte reine  Datenobjekte sind,  widerspricht streng
  128. genommen den Prinzipien von OOP: Diese Objekte enthalten nur Daten
  129. und keine Methoden;  die Daten werden  mit Direktzugriffen gelesen
  130. und  verändert.   Doch  der   Grund  liegt in  der
  131. Ausführungsgeschwindigkeit:  Die  Methoden  von "EventHandlerObj",
  132. die die Verwaltung  vornehmen, werden indirekt  von dem Ersatz für
  133. den  Interrupt  $09  (Keyboardinterrupt)  und  einem installierten
  134. Maushandler des Assemblermoduls "MouKeyAs.Asm" aufgerufen. Und bei
  135. der  Interruptbearbeitung  geht  es  bekanntlich  um  die maximale
  136. Ausführgeschwindigkeit. Deshalb  ausnahmsweise  der Bruch  mit der
  137. reinen objektorientierten  Programmierung.  Daß es  trotzdem noch
  138. Objekte sind und  keine Records, liegt  an der Erweiterbarkeit der
  139. Objekte. Ein  Kindobjekt  von  "EventObj" könnte  auch  noch fähig
  140. sein,   die   Informationen   eines   Lichtgriffel-Ereignisses  zu
  141. speichern. Wäre  "EventObj"  ein  Record,  wäre  diese Erweiterung
  142. nicht so einfach möglich.
  143.  
  144. Nur  wenige  Methoden  von   "EventHandlerObj"  werden  von  einem
  145. Programm benötigt werden; welche  das sind und  wie man Events vom
  146. Typ "EventObj" auswertet, das zeigt das Demoprogramm "MKDemo". Mit
  147. ihm  kann  man  gleichzeitig  eine  Liste  der  Events  und  ihren
  148. Auswertungen, z.B. Tastaturcodes,  erstellen. Wie für verschiedene
  149. Ereignisse ein  Handler  installiert wird,  demonstriert  auch das
  150. Demoprogramm.
  151.  
  152. Die  Unit   MouKey  versucht   immer,   ein  "MouseObj"   und  ein
  153. "EventHandlerObj" anzulegen. Auch hier gilt: Nur ein Eventhandler-
  154. Objekt pro  Programm  macht  Sinn, denn  mehrere  würden  alle die
  155. gleichen Ereignisse  bearbeiten. Damit  es  aber möglich  ist, ein
  156. erweitertes     Eventhandler-Objekt,     das     natürlich     von
  157. "EventHandlerObj"  erbt,  zu  verwenden,  gibt  es  "DeInstall" und
  158. "ReInstall". Analog für  die Maus  existieren "DeInstallMouse" und
  159. "ReInstallMouse", falls  man  ein eigenes,  erweitertes Mausobjekt
  160. benutzen will. Auch das wird in "MKDemo" demonstriert.
  161.  
  162.  
  163.                       4. UBuffer und DiskBuf
  164.                       ----------------------
  165.  
  166. Das Objekt  "Buffer" aus  der  Unit "UBuffer"  implementiert einen
  167. Puffer im normalen Heap. Es organisiert den Puffer zeilenweise und
  168. speichert  für  jedes  Zeichen  ein  Attribut.  Es  stellt  einige
  169. Fähigkeiten  zur  Verfügung,  die  sich  an  seiner  Methodenliste
  170. ablesen lassen. Einige Methoden sind  intern, sollten also nur von
  171. Nachkommen gebraucht  und  überschrieben werden.  Die  meisten der
  172. anderen  Methoden  sind  "Set-..."  oder  "Get-..."  Methoden, die
  173. einzelne Variablenwerte  setzen  oder lesen.  Am  wichtigsten sind
  174. wohl die  Methoden  "WriteStr"  und "WriteStrXY".  Die  Arbeit mit
  175. "Buffer" und auch mit "DiskBuf" demonstriert "BufDemo".
  176.  
  177. Wem der Hauptspeicher  zuwenig ist, der  kann "DiskBuf" einsetzen:
  178. Dieses Objekt lagert,  sobald  im  Heap  kein  Platz  mehr  ist,  auf die
  179. Festplatte oder Diskette (allerdings wegen der langsamen Lese- und
  180. Schreibzugriffe nicht  sehr ratsam)  aus  und arbeitet  gemixt mit
  181. Heap und Festplattenspeicher. Um all das braucht sich der Anwender
  182. von "DiskBuf" jedoch  nicht zu kümmern,  hauptsächlich wird er die
  183. Methoden benötigen,  die der  Vorfahre, "Buffer",  schon enthalten
  184. hat. Das  Auslagern  läuft  intern  ab,  sollte  nicht  von außen
  185. beeinflußt werden, nur über  die dafür vorgesehenen Methoden. Ist
  186. die Festplatte oder  Diskette voll, so  arbeitet "DiskBuf" weiter,
  187. nimmt aber keine  neuen Daten  mehr an. Nur  die schon vorhandenen
  188. Daten  können  noch  manipuliert  werden.  Dieser  Fehlerfall muß
  189. explizit mit  "GetErrorL1"  abgefragt  werden.  Liegt  ein anderer
  190. Fehler vor, z.B.  ungültiges Laufwerk, so  kann der Dos-Fehlercode
  191. mit  "GetDosError"  abgefragt  werden.  "GetErrorL1"  liefert  nur
  192. "BufFileErr" zurück.
  193.  
  194.  
  195.                              5. Lists
  196.                              --------
  197.  
  198. Um eine einfach  verkettete Liste  zu verarbeiten,  braucht es ein
  199. Knotenobjekt,  das  einen  Zeiger  auf  das  nächste  Knotenobjekt
  200. enthält ("SListNode"). "DListNode"  erweitert "SListNode" um einen
  201. "Rückwärtszeiger"  auf  den  Vorgängerknoten.  Die  Aufgabe dieser
  202. Objekte besteht  nur  darin,  diese Knoten  zu  speichern  und auf
  203. Anfrage bekanntzugeben.
  204.  
  205. Es wäre möglich,  daß eine  Liste nun Einträge  verlangt, die von
  206. diesen Objekten abgeleitet sind und somit immer den Zeiger auf das
  207. nächste oder vorhergehende  Objekt im Glied  der Liste automatisch
  208. auch enthalten. Doch  man kann die  Abschottung weiter treiben, so
  209. daß  die  zu  verwaltenden  Objekte  überhaupt  nicht  zu  wissen
  210. brauchen, wie  sie verwaltet  werden. Das  heißt, sie  kennen die
  211. Knoten nicht, sondern  können ganz normal  von "Base" erben. Sonst
  212. müßte man alle Objekte von "SListNode" oder "DListNode" statt von
  213. "Base" ableiten. Das wäre sicherlich nicht wünschenswert.
  214.  
  215. "SListNode" enthält zusätzlich einen Zeiger auf ein Objekt vom Typ
  216. "Base". Auf was für einen Objekttyp dieser Zeiger nun zur Laufzeit
  217. wirklich zeigt,  spielt für  "SListNode"  keine Rolle,  das Objekt
  218. stammt von "Base" ab, also kann sein Destruktor aufgerufen werden,
  219. sobald derjenige  von  "SListNode" aufgerufen  wird.  Mehr braucht
  220. "SListNode" von  dem Objekt,  für  das es  den Knoten  bildet, gar
  221. nicht  zu   wissen.  Natürlich   entsteht  dadurch   ein  gewisser
  222. "Overhead", doch den muß man in Kauf nehmen.
  223.  
  224. Hier wird  deutlich sichtbar,  was für  einen enormen  Vorteil die
  225. Verwendung  eines  abstrakten   Objekts  "Base"   als  Vater  oder
  226. Grossvater oder auch  Urur...grossvater mit sich  bringt: Alle von
  227. "Base"  erbenden   Objekte   können  mit   demselben  Listenobjekt
  228. verwaltet werden. Polymorphie macht's möglich !
  229.  
  230. Wenn   man   eine    objektorientierte   Toolbox   eines   anderen
  231. Programmierers benutzt  und  dieser  sich an  das  gleiche Prinzip
  232. gehalten hat  (also  auch  einen Grundtypen  in  seiner Hierarchie
  233. führt), kann man  eigene Objekt  schnell an  die Toolbox anpassen:
  234. Das eigene  "Base" von  dem Baseobjekt  der Toolbox  erben lassen,
  235. alle eigenen  Units neu  compilieren, und  schon steht's  - na ja,
  236. ganz so einfach dürfte's nicht sein, aber trotzdem...
  237.  
  238. "AbstractList"  ist  ein   Grundobjekt  für  Listen  verarbeitende
  239. Objekte.  Es  enthält  nur  das  Protokoll,  das  allen  von  ihm
  240. erbenden,  Listen   verwaltenden   Objekten   gleich   sein  muß.
  241. "DListCollection" trägt  die  Objekte  in der  Reihenfolge  in die
  242. doppelt verkettete Liste ein,  in der sie  mit "Put" oder "Insert"
  243. hinzugefügt werden. Um aber  bequem mit einer doppelt verketteten,
  244. nicht sortierten  Liste arbeiten  zu können,  sind einige Methoden
  245. zusätzlich notwendig,  z.B.  um sich  durch  die Liste  hangeln zu
  246. können ("GetNext/Prev-Node/Data").
  247.  
  248. Die Anwendung  von  "DListCollection"  demonstrieren "RadioButton"
  249. und "DialogBox".
  250.  
  251.  
  252.                         6. Units aus \VSMS
  253.                         ------------------
  254.  
  255. Dieses Kapitel ist nach Objekten geordnet. Alle Objekte sind in
  256. einer eigenen Unit implementiert. Der Namen der Unit ist in der
  257. Hierarchie festgehalten.
  258.  
  259. ∙ "VirtualScreen"  ist  ein  im  Heap  lebender  "Bildschirm". Zur
  260.   Beschreibung dieses Bildschirms sind  wenig Daten nötig. Wichtig
  261.   ist  die  Ausdehnung  des  (virtuellen)  Bildschirms.  Zu seiner
  262.   "Bearbeitung" sind jedoch um so mehr Methoden (zum Schreiben von
  263.   Zeichen und  Strings, zum  Füllen von  Bereichen ...) notwendig.
  264.   Der "Init"-Konstruktor versucht, Speicher  für den Bildschirm zu
  265.   allokieren.  Schlägt  dieser   Versuch  fehl,   so  wird  "Fail"
  266.   aufgerufen.  Der   belegte   Speicher  wird   von   "Done"  wieder
  267.   freigegeben.
  268.  
  269. ∙ "ScrObj" braucht  keinen Heap, sondern  benutzt als Speicher den
  270.   Bildschirmspeicher.   In    "Init"    wird    automatische   die
  271.   Anfangsadresse des  Bildschirmspeichers ermittelt.  "ScrObj" ist
  272.   also ein  "Modell" des  wirklichen Bildschirms.  Was in "ScrObj"
  273.   ausgegeben werden soll, wird auf dem Bildschirm sichtbar (es sei
  274.   denn, man  hat auf  eine Bildschirmseite  ungleich der "nullten"
  275.   umgeschaltet). "Init" und "Done"  wurden ganz überschrieben, die
  276.   Vorgängermethoden  werden  nicht  mehr  aufgerufen,  da "ScrObj"
  277.   keinen  Speicher  benötigt,  weil  es  den  richtigen Bildschirm
  278.   "darstellt", für den der  Speicher hardwaremäßig reserviert ist.
  279.   Also braucht Speicher weder belegt noch freigegeben zu werden.
  280.  
  281. ∙  Interessanter  sind   die  Verwaltungen  der  "VirtualScreen"s.
  282.   "VSManagerObj" implementiert  nur die  nötigsten Methoden dieser
  283.   Verwaltung,  wie   "AddVS",   "DeleteVS"  und   "SelectVS".  Der
  284.   Einfachkeit halber werden die virtuellen (und auch der richtige)
  285.   Bildschirm  in  einem  Array   verwaltet,  die  maximale  Anzahl
  286.   virtueller  Bildschirme  ist  also  schon  zur  Compilationszeit
  287.   festzulegen. Möglich  wäre auch  die Verwaltung  in einer Liste,
  288.   doch lohnt sich der dabei  entstehende Mehraufwand nicht. Da der
  289.   Array  nur  Zeiger  enthält,  vergibt  man  sich  nicht  zu viel
  290.   Speicher, setzt man die Obergrenze z.B. auf 100 fest.
  291.  
  292. ∙ "ExtVSManager erweitert  "VSManagerObj" um "Weiterleitungen" von
  293.   "WriteChr", "WriteStr"  und  ähnlichen Methoden  an  den aktuell
  294.   selektierten (aktiven) virtuellen Bildschirm, der natürlich auch
  295.   der  richtige   Bildschirm  sein   kann.  Was   für  (virtuelle)
  296.   Bildschirme verwendet  werden, ist  für die  "Verwaltungen" ohne
  297.   Bedeutung. Wer  also z.B.  ein  Objekt "ExtVGAScrObj"  für einen
  298.   exotischen  Textmodus   von   "ScrObj"  ableitet,   kann  dieses
  299.   benutzen, ohne  daß  "VSManagerObj"  oder  "ExtVSManager" etwas
  300.   davon merken. Werden Bildschirmausschnitte kopiert, ist das kein
  301.   Problem,  da   "ExtVSManager"   immer  auf   den  Zielbildschirm
  302.   Rücksicht nimmt.
  303.  
  304. ∙ "VSMCrt",  ein  Kindobjekt  von  "ExtVSManager",  ist  eine fast
  305.   100%ige Nachbildung der Unit "Crt" von Turbo Pascal; die einzige
  306.   Prozedur die fehlt, ist "AssignCrt".  Ansonsten kann man mit dem
  307.   Objekt völlig  analog zur  Unit "Crt"  arbeiten, wenn  man davon
  308.   absieht, daß  Variablen  (dem  Prinzip  der  Abschottung folgend)
  309.   nicht wie  z.B. die  Variable "TextAttr"  der Unit  "Crt" direkt
  310.   geändert werden  sollten,  sondern  mit  den  dafür vorgesehenen
  311.   Methoden, also für dieses  Beispiel "SetTextAttr" zum Setzen und
  312.   "TextAttr" (eine Funktion !) zum Abfragen.
  313.  
  314. ∙ "WinVSM" schließlich erweitert "VSMCrt" nur um die von Fenstern
  315.   benötigte Fähigkeit,  einen  Ausschnitt  des  aktiven virtuellen
  316.   Bildschirms zu  speichern und  wieder herzustellen.  Es erbt von
  317.   "VSMCrt", damit den Fenstern alle Fähigkeiten der Unit "Crt" zur
  318.   Verfügung stehen.
  319.  
  320. ∙ Eine  Demo  für  "VSMCrt" bildet  die  leicht  umgestrickte Demo
  321.   "CrtDemo" von  Turbo Pascal:  Sie  zeigt, wie  VSMCrt eingesetzt
  322.   wird und  wo  (noch)  ihre  Grenzen  liegen:  Spezialzeichen wie
  323.   Backspace werden nicht interpretiert, sondern ausgegeben.
  324.  
  325.  
  326.                               7. SB
  327.                               -----
  328.  
  329. Das Objekt  "ScrollBarObj" ist  eine Art  "halb-abstraktes" Objekt:
  330. Die entscheidenden Methoden, wie  die Anzeige des Scrollbalken auf
  331. dem  Bildschirm,  sind  noch   nicht  enthalten.  Das  müssen  die
  332. spezialisierten Nachkommen  "HorizScrollBar" und "VerticScrollBar"
  333. übernehmen; erst sie wissen,  ob y1=y2 oder  x1=x2 gilt, damit die
  334. Koordinaten gültig sind. Analoges  gilt für alle anderen Methoden,
  335. die mit den Koordinaten  hantieren. "ScrollBarObj" wurde als Vater
  336. der beiden eingeführt,  da sie doch  einiges gemeinsam haben, z.B.
  337. die Abfrage der  Positionen oder das  Setzen von Farben. Abgesehen
  338. davon  wird   der   Stammbaum  der   Scrollbalken-Familie  dadurch
  339. logischer;  die  Gemeinsamkeiten   der  beiden  Scrollbalken-Arten
  340. werden schon in der Hierarchie sichtbar. Ausserdem ist der Einsatz
  341. flexibler, eine  Instanze vom  Typ  "ScrollBarObj" kann  auf beide
  342. Nachfahren initialisiert werden.
  343.  
  344. Wie diese Nachfahren von  "ScrollBarObj" angewendet werden, ist in
  345. "DataWindow" demonstriert.
  346.  
  347.  
  348.                       8. Units aus \WINDOWS
  349.                       ---------------------
  350.  
  351. Demonstrationsprogramme finden  sich im  Unterverzeichnis DEMOS zu
  352. allen Fensterobjekten  bis  auf "SAAWindow".  Diese  Demos genauer
  353. auszuprobieren lohnt sich besonders bei den aktiven Fenstern.
  354.  
  355. ∙ "FrameWindow" als direkter Erbe von "Base" ist der Ausgangspunkt
  356.   für die lange nachfolgende Vererbungskette. Es ist ein "Fenster"
  357.   einfachster Art, wobei die Bezeichnung Fenster schon eine kleine
  358.   Übertreibung ist, da  es den  Hintergrund nicht  retten kann. Es
  359.   kümmert sich nur  um die  Darstellung des  Fenstersrahmens und -
  360.   schattens auf  dem  Bildschirm,  um  die  grundlegenden Elemente
  361.   eines   jeden   Fensters   (Kopf-   und   Fußzeile,  Rahmenart,
  362.   Schattenflag usw).
  363.  
  364. ∙ "WindowObj" erweitert "FrameWindow"  zu einem richtigen Fenster,
  365.   das den Hintergrund  speichern, beim  Öffnen automatisch löschen
  366.   und beim Schließen wiederherstellen kann, sofern diese Aktionen
  367.   überhaupt  gewünscht   sind.   Die   andern,  neu hinzugekommenen
  368.   Methoden kümmern sich nur um das Setzen und Abfragen der eigenen
  369.   Flags.
  370.  
  371. ∙ Weiter in  der Kette der  logischen Erweiterungen bildet "Stand-
  372.   ardWindow" das nächste  Glied der  Kette. Es  geht einen Schritt
  373.   weiter als  "WindowObj": Als  Standard-Fenster nach  SAA ist ihm
  374.   zusätzlich die Möglichkeit spendiert worden, sich zu verschieben
  375.   und zu  verkleinern/verkleinern,  beides  relativ  oder absolut.
  376.   Dabei ist es  möglich, den Bewegungsraum  und damit die maximale
  377.   äußere Größe einzuschränken und  die minmale innere Ausdehnung
  378.   festzulegen. Der Grund dafür ist der, dass z.B. die Menüzeile in
  379.   einem Programm  nicht von  Fenstern  überdeckt werden  soll. Und
  380.   wenn das  Fenster einen  Inhalt  hat, ist  es meist  nicht allzu
  381.   sinnvoll, eine Mindestgröße zu unterschreiten.
  382.  
  383. ∙ "ActiveStandWin" ist  wiederum eine  konsequente Erweiterung von
  384.   "StandardWindow":  Die   Abfrage   von  Events   in   Bezug  auf
  385.   Fähigkeiten  des   Standardfensters   (verschieben,  schließen,
  386.   vergrößern) kann "ActiveStandWin"  selbständig vornehmen. Durch
  387.   die Anzeige des  "Close"-Symbols ("[■]") in  der Titelzeile wird
  388.   angezeigt, daß es  sich um  ein Fenster  handelt, das reagieren
  389.   kann. Die Abfrage,  ob ein  Event das  Fenster betrifft, erfolgt
  390.   mit der Methode  "CheckEvent". Es wird  nur reagiert, sofern das
  391.   Fenster aktiv  ist,  d.h. durch  einen  doppelten, hervorgehobenen
  392.   Rahmen gekennzeichnet ist.  Der Zustand  (aktiv/passiv) kann nur
  393.   durch  den  Aufruf   der  entsprechenden  Methode  ("SetActive"/
  394.   "SetPassive")  umgeschaltet   werden.   Die   Demo   zeigt,  wie
  395.   "ActiveStandWin"  angewandt  wird   und  wie  seine  Returncodes
  396.   ("Antworten") ausgewertet werden.
  397.  
  398. ∙ Einen  weiteren  Schritt  in der  Fensterevolution  macht "Data-
  399.   Window":   Es   verknüpft   "Buffer"   bzw.   "DiskBuffer"   mit
  400.   "ActiveStandWin". Deswegen sind auch soviele Methoden vorhanden:
  401.   Viele "Messages" wie "WriteStr", "DelLine", etc. müssen nur an das
  402.   Buffer-Objekt  weitergereicht   werden.  Die   anderen  Methoden
  403.   kümmern sich um die Verknüpfung der beiden "Ehepartner" "Buffer"
  404.   und "Window",  so z.B.  "ShowBuffer",  "ScrollBuf" ...  Dazu ist
  405.   einiges an internen Methoden nötig. Ein ganzes Set von "Set-..."
  406.   und "Get-..."  Methoden  steht  für die  Manipulation  der neuen
  407.   Daten zur Verfügung. "DataWindow" verfügt auch über "ScrollBar"-
  408.   Objekte, die  die relative  Pufferposition anzeigen  sollen. Auf
  409.   Wunsch  kann   auch  die   absolute  Position   in  der  unteren
  410.   Fensterzeile eingeblendet werden.
  411.  
  412. ∙ Das letzte hier implementierte  Objekt dieser Kette geht  -
  413.   wie sollte es anders sein - einen logischen Schritt weiter: Nun ist es
  414.   ein  "ActiveDataWindow"  geworden,  das  Events  um  die in
  415.   "DataWindow" erweiterten  Fähigkeiten  abfragt; so  z.B.  ob der
  416.   Scrollbalken mit der Maus betätigt  wurde. Neu sind hier die
  417.   Symbole, die  mit  der Maus  angeklickt  werden können,  es sind
  418.   Symbole,   die   das    "Normalisieren",      "Maximieren"   und
  419.   "Iconisieren"   (verschiedene   Grössenstufen)   anzeigen.   Die
  420.   Mausabfrage,  die  doch   ziemlich  aufwendig   ist,  wurde  auf
  421.   veschiedene interne  Methoden  verteilt, so  daß  ein Nachkomme
  422.   gezielt bestimmte  Eigenschaften verändern  kann. Soll  z.B. das
  423.   Fenster nicht mehr per Doppelklick die Größe verändern, so kann
  424.   "CheckMouDoublC" überschrieben werden.
  425.  
  426.  
  427. ∙   "SAAWindow"   ist    von   "ActiveStandWin"   abgeleitet   und
  428.   unterscheidet sich nur in  einem einzigen Punkt: Ein "SAAWindow"
  429.   ist immer  aktiv, kennt  keinen  Unterschied in  der Darstellung
  430.   zwischen aktiv und passiv. Ein  Beispiel, wo diese Sturheit Sinn
  431.   macht: So  soll die  Eingabe in  einen "WindowInputField" zuerst
  432.   beendet werden,  bevor  woanders mit  der  Arbeit weitergefahren
  433.   wird. Dazu  ein Vergleich  mit  Turbo Pascal:  Ist man  in einen
  434.   Eingabefeld, so ist - bis auf F1 - alles andere tot, zuerst muß
  435.   man das Eingabefeld schließen, sei es per Esc oder Enter.
  436.  
  437.  
  438. Ein anderes  Design  dieser  ziemlich  lange  Vererbungskette wäre
  439. natürlich auch möglich. Eine  Möglichkeit wäre z.B., "FrameWindow"
  440. in Teile aufzuspalten: "DisplayElement", davon ein "Title"-Objekt,
  441. ein  Rahmenobjekt  und  ein  Hintergrundobjekt  usw.  ableiten. Des
  442. weiteren könnten die Symbole  ("Close", "Maximize"...) in einzelne
  443. Objekte gepackt  werden,  und "DataWindow"  und "ActiveDataWindow"
  444. ganz neu  aus anderen  Teilen  zu einer  Baugruppe zusammengesetzt
  445. werden. Der  Vorteil  dieses  Designs  wäre,  daß  man  die lange
  446. Vererbungskette vermeidet. Denn dadurch werden die Objekte "weiter
  447. hinten" sehr schnell  sehr komplex,  "DataWindow" z.B.  hat um 120
  448. Methoden.  Der  Nachteil:  Man  erhält  sehr  schnell  sehr  viele
  449. Objekte, also eine  riesige Hierarchie.  Also entweder Komplexität
  450. der Hierarchie  -  oder  Komplexität  der  Objekte  tiefer  in der
  451. Vererbungskette.
  452.  
  453. Doch  der  Vorteil  des  hier  verwendeten  Design  liegt  in  der
  454. konsequenten, stufenweisen  und  logischen  Erweiterung  von einer
  455. Objektstufe zur  nächsten,  wie es  bei  einer Treppe  immer einen
  456. Schritt höher geht. Und die sonst schon ziemlich große Hierarchie
  457. sollte nicht noch  grösser werden.  Aus diesen  Gründen ist dieses
  458. Design auch gewählt worden.
  459.  
  460.  
  461.                            9. SAAItemD
  462.                            -----------
  463.  
  464. "SAAItem" bildet  die  Grundlage für  alle  "Einträge", sei  es in
  465. Menüs, in Dialogboxen  oder was  auch immer.  Es implementiert die
  466. allen Nachkommen gemeinsamen  Methoden wie  das Anzeigen ("Show"),
  467. das Prüfen,  ob der  HotKey betätigt  wurde ("CheckKeyEv),  ob ein
  468. Mausknopf   im   eigenen   Bereich   niedergedrückt   worden   ist
  469. ("CheckMouEv") usw. Auf diesem  Objekt aufbauend fügen seine Erben
  470. nur noch ganz spezifische Methoden,  die sie benötigen, hinzu oder
  471. implementieren ererbte Methoden neu.
  472.  
  473. Das gemeinsame Grundobjekt dient auch der Listenverarbeitung, denn
  474. in den Schedulern (s.u.) braucht  man einen gemeinsamen Nenner für
  475. alle Einträge.  Dieser kleinste  gemeinsame Nenner  ist "SAAItem".
  476. Über ihn spricht ein Scheduler  seine Einträge an, ohne zu wissen,
  477. welchen Typs sie  eigentlich sind. Da  die entsprechenden Methoden
  478. virtuell sind,  ist  das  aber  auch  überhaupt  nicht  nötig. Zur
  479. Laufzeit wird  die Methode  des betreffenden  Objekttyps ausfindig
  480. gemacht und  aufgerufen. Das  ganze  nennt sich  bekanntlich "Late
  481. binding"   und   läuft    mit   Hilfe    der   "VMT"   (virtuellen
  482. Methodentabelle).
  483. Hätte  man   diesen  gemeinsamen   Nenner  nicht   eingeführt  und
  484. stattdessen  die  spezialisierten  Nachkommen  direkt  von  "Base"
  485. abgeleitet, wäre man innerhalb des Schedulers wieder bei den guten
  486. alten "IF THEN ELSE IF"-Statements in der Art
  487.  
  488.   IF TypeOf (Item)=TypeOf (MenuItem) THEN
  489.     MenuItemPtr (ItemPtr)^.Display
  490.   ELSE
  491.     IF ...
  492.  
  493. angelangt. Der ganze  Vorteil von  OOP wäre  zunichte gemacht, die
  494. Polymorphie mit den Füßen getreten.  An diesem Beispiel sieht man
  495. sehr eindrücklich,  daß es  sich  wirklich lohnt,  abstrakte oder
  496. auch "halb-abstrakte" Objekte in die Hierarchie einzufügen.
  497.  
  498.  
  499.                            10. MnuItems
  500.                            ------------
  501.  
  502. Wie  die  einzelnen  Objekte  aus  der  Unit  "MnuItems" angewandt
  503. werden, zeigen die Demoprogramme in dem Unterverzeichnis DEMOS.
  504.  
  505. ∙ "MenuItem"  ist seinerseits  ein Oberobjekt  für alle  Arten von
  506.   Menüeinträgen und hat gleichzeitig  die Eigenschaften eines SAA-
  507.   Eintrages. Deshalb ist  es ein  Erbe von "SAAItem".  Es ist aber
  508.   auch noch kein  konkretes, sondern  ein "halbabstraktes" Objekt,
  509.   das den  Menüschedulern  die  Verwaltung  erleichtert  (wie oben
  510.   anhand von "SAAItem"  erläutert). Anders als  bei "SAAItem" wird
  511.   hier bei  "SetActive" die  Darstellung geändert,  der Item durch
  512.   einen "Balken" farblich hervorgehoben.
  513.  
  514. ∙ Ein drittes halbabstraktes  Objekt nach "SAAItem" und "MenuItem"
  515.   ist  "PopUpItem",   das  von   "MenuItem"  erbt.   Allen  seinen
  516.   Nachkommen ist  gemeinsam, daß  sie  bei Betätigung  von "Cursor
  517.   hoch"  bzw.  "Cursor  runter"  den  Returncode  "ActNext"  bzw. "ActPrev"
  518.   zurückgeben. Ein  vertikales Menü  kennt verschiedene  Arten von
  519.   Einträgen,   und   diese   sind   als   Erben   von  "PopUpItem"
  520.   spezialisiert. "PopUpItem"  dient nur  als gemeinsame Grundlage,
  521.   damit die Abfrage  auf Cursor  rauf oder runter  nicht von jedem
  522.   Nachkommen von "PopUpItem" selbst vorgenommen werden muß.
  523.  
  524. ∙ Nach  einem abstrakten  Objekt ("Base")  und drei halb-abstrakten
  525.   ("SAAItem"-"MenuItem"-"PopUpItem") ist "ExeItem" ein "konkretes"
  526.   Objekt. Es stellt  einen Menüeintrag dar,  der bei seiner Anwahl
  527.   eine Aktion auslösen soll ("ExecutableItem", natürlich ist nicht
  528.   der Item  ausführbar, sondern  die hinter  seinem Namen stehende
  529.   Funktion soll ausgeführt werden).
  530.  
  531. ∙ Ein spezialisierter Nachfahre von "ExeItem" ist "DirectExeItem".
  532.   Ein solcher Menüeintrag kann noch zusätzlich zu Maus, Hotkey und
  533.   Alt+Hotkey mit einem "DirectCode" ausgeführt werden. Ein solcher
  534.   Menüpunkt kann auch  gewählt werden, wenn  sein PopUp-Menü nicht
  535.   aktiv (angezeigt)  ist, wohingegen  die HotKey-Wahl  nur für das
  536.   gerade aktive PopUp-Meü möglich ist. Ein Beispiel dafür ist Alt-
  537.   F3  in  Turbo   Pascal  5.5:  Die   Picklist  erscheint  direkt,
  538.   unabhängig davon, ob man gerade im "File"-Menü ist oder nicht.
  539.  
  540. ∙ "SwitchItem" ist ein Item, der zwei Zustände aufweist: "On" oder
  541.   "Off" (Beispiel bei Turbo  Pascal: "Stack Checking On/Off"). Bei
  542.   der Wahl mit Enter wird nur der Zustand geändert, nicht aber die
  543.   Menüwahl beendet.
  544.  
  545. ∙ "GlobalSwitchItem" als Nachkomme von "SwitchItem" schaltet nicht
  546.   nur das eigene  Flag um,  sondern auch  eine Boolesche Variable,
  547.   auf  die  es  einen  Pointer  enthält.  So  können  Modul-  oder
  548.   Programmglobale Variablen  direkt abgefragt  bzw. weiterverwendet
  549.   werden,  ohne   daß  die   Resultate   immer  erst   aus  einem
  550.   "SwitchItem" in diese Variablen kopiert werden müssen.
  551.  
  552. ∙ "LineItem" stammt  von "PopUpItem"  und ist  ein Trennstrich für
  553.   ein Menü. Er kann auf keine  Art und Weise aktiviert werden, hat
  554.   keinen Hotkey, keinen  Namen, einfach nichts.  Wird mit der Maus
  555.   versucht, ihn  zu  aktivieren,  so teilt  er  dem übergeordneten
  556.   Popup-Menü  mit,  daß  es  "sich  beenden"  soll  (ReturnCode =
  557.   "ItFinish").
  558.  
  559. ∙ "SlideBarItem" ist ein direkter Nachkomme von "MenuItem" und hat
  560.   es wesentlich  einfacher als  die vielen  "PopUpItem"-Arten: Ein
  561.   horizontales Menü kann nur aus "ExeItem"s bestehen, die alle das
  562.   gleiche tun: Sie öffnen ein Untermenü.
  563.  
  564.  
  565.                            11. DbxItems
  566.                            ------------
  567.  
  568. ∙ "RadioBut",  "PushBut"  und "EndBut"  sind  Implementationen der
  569.   verschiedenen Button-Typen  und  stammen von  "SAAItem"  ab. Sie
  570.   alle sind Einträge, aber nicht wie die Nachkommen von "MenuItem"
  571.   in einem Menü, sondern in irgendeiner Dialogbox.
  572.  
  573.   Es ist nicht direkt einsichtig, warum "PushBut" und "EndBut" als
  574.   Buttons   implementiert   wurden,   wo   doch   ihre   Scheduler
  575.   ("PushButton"   und   "EndButton")   praktisch   nur   noch  aus
  576.   Weiterleitungen der Messages  besteht. Daß sie  denoch hier von
  577.   "SAAItem" abgeleitet sind, hat den Grund, daß die Dialogbox mit
  578.   Schedulern kommunizieren will, und  diese sich wiederum nicht um
  579.   Kleinigkeiten  wie  Position  oder  Farbe  kümmern  sollten. Den
  580.   Schedulern ist  es egal,  welche Art  Items sie  beherbergen. Es
  581.   werden  eher   Änderungen   an  den   Items   (in  irgendwelchen
  582.   Kindobjekten) nötig  sein als  an  ihren Schedulern,  denn diese
  583.   kümmern sich nur um verwaltungstechnische Aspekte, nicht aber um
  584.   die Darstellungsart,  die  Art  zu reagieren  usw.  Das  ist die
  585.   Aufgabe eines Items.
  586.  
  587. ∙  Um   einen  String   konfortabel   editieren  zu   können,  ist
  588.   "StringField"   da.   Es    implementiert   ein   vollständiges,
  589.   einzeiliges  Editerfeld.  Auch  ein  Eingabefeld,  z.B.  für die
  590.   Eingabe eines Dateinamens, ist  ein Bestandteil einer DialogBox.
  591.   Aus den gleichen  Gründen, die  oben für  "PushBut" und "EndBut"
  592.   Ausschlag gebend  waren, ist  auch "StringField"  ein Item. Sein
  593.   Scheduler hat  ein  leichtes  Spiel,  braucht  er  doch  nur die
  594.   "Messages" weiterzugeben.
  595.  
  596. ∙  "IntegerField"   und  "RealField",   Kinder  von  "StringField"
  597.   versuchen nach  Beendigung der  Eingabe, diese  in eine Integer-
  598.   oder Real-Zahl umzuwandeln. Bei der  Eingabe lassen sie nur noch
  599.   Zahlen,   Vorzeichen   und   RealField   zusätzlich   noch   den
  600.   Dezimalpunkt zu.
  601.  
  602. ∙  "PickList"  ist  wohl  der   komplexeste  Item.  Aus  den  oben
  603.   angeführten Gründen ist auch hier ein "Item" zwischengeschaltet.
  604.   Die  Pickliste   enthält  einen   vertikalen  Scrollbalken.  Die
  605.   einzelnen  Einträge   in   die   Pickliste   werden   mit  "Add"
  606.   vorgenommen. Trotz seiner  Komplexität ist  "PickList" leicht zu
  607.   benutzen, wie sein Scheduler "PickListSched" demonstriert.
  608.  
  609. ∙ "ExtPickList"  fügt  seinem  Vaterobjekt  "PickList"  noch einen
  610.   horizontalen Scrollbalken  hinzu. "StandAlonePickList" erweitert
  611.   "ExtPickList" dahingehend,  dass das  Fenster ein  aktives, also
  612.   selbständiges  Fenster   ist,  das   nicht  in   eine  Dialogbox
  613.   integriert ist.
  614.  
  615.   Hier wäre  auch  ein  anderes Design  einsichtig:  Ein Picklist-
  616.   Eintrag wäre ein Erbe von SAAItem, die Pickliste selbst aber von
  617.   SAAScheduler abgeleitet. Ein solcher PickListItem wäre aber auch
  618.   ziemlich  aufwendig  geworden,  da  er  viel  von  dem  jetzigen
  619.   "PickList"-Objekt hätte übernehmen  müssen. Ausserdem wären dann
  620.   viele Daten wie  die Farbe unnötig  oft (von jedem PickListItem)
  621.   gespeichert worden.
  622.  
  623.   Außerdem ist es  mit dem  hier verwendeten  Design möglich, dem
  624.   Picklist-Scheduler alle  Arten  von  Picklisten unterzuschieben,
  625.   ohne daß er  dafür geändert werden  müßte. Für ihn  kommt es -
  626.   wie für so  viele andere Objekte  - nicht darauf  an, zu welchem
  627.   Objekttyp die Methoden gehören,  die er aufruft. Das entscheidet
  628.   der ihm in "Init" übergebene Item.
  629.  
  630.  
  631.                            12. SAASched
  632.                            ------------
  633.  
  634. "SAAScheduler"   ist   wieder   ein   halb-abstraktes   (eigentlich
  635. dreiviertel-abstraktes)  Objekt,   das  als   Grundlage  für  alle
  636. Scheduler dient. Sehr viele Methoden  braucht es nicht, um mit ihm
  637. umgehen zu  können.  Die  Komplexität,  die  hinter  einem solchen
  638. Scheduler und  seinem(n) Item(s)  stehen, bleibt  für den Anwender
  639. eines Nachkommen  von  "SAAScheduler" verborgen,  er  braucht sich
  640. nicht darum zu kümmern. Er weiß, welche Methoden welche Parameter
  641. erfordern und was sie  machen. Mehr ist nicht  nötig, es sei denn,
  642. er will  die Scheduler  oder  Items erweitern.  Dann muß  er sich
  643. genauer mit dem Aufbau eines Objekts beschäftigen.
  644.  
  645.  
  646.                            13. DBxSched
  647.                            ------------
  648.  
  649. Auch hier sind es  wieder kleine Demoprogramme im Unterverzeichnis
  650. DEMOS, die den Gebrauch der Objekte aus "DBxSched" demonstrieren.
  651.  
  652. ∙ "RadioButtons" ist ein etwas komplexerer Scheduler. Da Items vom
  653.   Typ   "RadioBut"   immer   nur   in   Gruppen   auftreten,  muss
  654.   "RadioButtons" diese verwalten.  Dadurch fällt  das Prüfen eines
  655.   Events etwas umfangreicher  aus. Kann der  aktive Item das Event
  656.   nicht auswerten  oder war  gar kein  Item aktiv,  so müssen alle
  657.   durchlaufen  werden,  um  zu  prüfen,  ob  sich  irgendein  Item
  658.   angesprochen fühlt. Dabei  wird ein  Item, der  schon aktiv war,
  659.   auch noch  einmal abgefragt.  Doch  die paar  Mikrosekunden, die
  660.   dafür verschwendet werden,  sind nicht  der Rede  wert. Hat sich
  661.   nun ein Item gefunden,  der das Event  auswerten konnte, so muß
  662.   der vorher  aktive noch  passiv gesetzt  werden. Der "RadioBut",
  663.   der das  Event  auswerten  konnte, hat  sich  selber automatisch
  664.   aktiv gesetzt.
  665.  
  666. ∙ "PushButton" und  "EndButton" haben es  wesentlich einfacher. Da
  667.   ihre Einträge  immer nur  alleine auftreten,  brauchen sie keine
  668.   Liste mit Einträgen zu  verwalten. Die meisten "Messages" können
  669.   einfach an  ihren  Eintrag  weitergeleitet werden.  Was  für ein
  670.   Eintrag das  ist, entscheidet  der an  "Init" übergebene Zeiger.
  671.   Werden  Kindobjekte  von  "PushBut"  oder  "EndBut"  benutzt, so
  672.   spielt das für "PushButton" oder "EndButton" keine Rolle.
  673.  
  674. ∙ Das gleiche gilt  für "InputField". "WinInputField" braucht sich
  675.   auch  nur  um  das  Fenster   zu  kümmern,  der  Rest  läuft  in
  676.   "StringField" oder dessen Nachkommen ab.
  677.  
  678. ∙  Auch  "PickListSched"  muß  die  meisten  Methodenaufrufe  nur
  679.   weiterleiten. "FileList"  erstellt  automatisch  eine  Liste von
  680.   allen Dateien  aus einem  Verzeichnis, und  "DirList" eine Liste
  681.   mit allen Directories aus einem Verzeichnis.
  682.  
  683. ∙ Das DialogBox-Objekt "DialogBox" ist dem RadioButton-Objekt sehr
  684.   ähnlich, die  Verwaltung  und  die Auswertung  von  Events läuft
  685.   praktisch analog ab.  Nur müssen die  Einträge einer "DialogBox"
  686.   vom Typ "SAAScheduler" (oder  dessen Nachkommen natürlich) sein.
  687.   "RadioButton"  im  Gegensatz  dazu  verlangt  Einträge  vom  Typ
  688.   "RadioBut".
  689.  
  690. ∙ "DialogEndBut"  fügt den  eingetragenen Scheduler  automatisch 2
  691.   oder 3 (mit  HelpButton) "EndButton" hinzu,  so daß diese nicht
  692.   jedesmal explizit angelegt werden müssen.
  693.  
  694. ∙  "SaveBox"  braucht   eine  Dialogbox  und   besteht  aus  einem
  695.   Eingabefeld für den Dateinamen, einer Pickliste für die Wahl des
  696.   Verzeichnisses und  2 oder  3 Endbuttons.  "SaveBox" macht nicht
  697.   viel mehr,  als diese  Einträge  in eine  Dialogbox einzutragen.
  698.   Seine Anwendung demonstriert "SBDemo".
  699.  
  700. ∙ Daß eine  "LoadBox" von  einer "SaveBox" erbt,  scheint von der
  701.   logischen Seite her nicht viel Sinn zu machen, erfüllen sie doch
  702.   zwei gegensätzliche  Aufgaben: Laden  und Speichern.  Schaut man
  703.   sich aber an,  was sie enthalten,  so stellt man  fest, daß die
  704.   "LoadBox" bis auf  eine Pickliste mit  Dateinamen fast identisch
  705.   mit der "SaveBox"  ist. Das  Eingabefeld ist nicht  mehr für den
  706.   Dateinamen da, sondern  für die Suchmaske,  doch der Rest bleibt
  707.   sich  gleich.  Das  ist  auch  der  Grund,  warum  "LoadBox" von
  708.   "SaveBox" erbt.
  709.  
  710.  
  711.                            14. MnuSched
  712.                            ------------
  713.  
  714. ∙ "MenuScheduler" implementiert die  für vertikale und horizontale
  715.   Menüs gemeinsamen Methoden,  z.B. das Auswerten  von Events, das
  716.   für beide fast  das gleiche  ist: ActNext und  ActPrev müssen ja
  717.   nicht wissen, was  für Items  da aktiviert werden.  In der Liste
  718.   geht vor- oder rückwärts, auf dem Bildschirm auf- oder abwärts.
  719.  
  720. ∙ "PopUpMenu" lässt  nur Einträge  vom Typ  "PopUpItem" und dessen
  721.   Nachkommen zu, "SlideBarMenu" will nur "SlideBarItem"s haben.
  722.  
  723.  
  724.                      Ein Ausblick, Anregungen
  725.                      ------------------------
  726.  
  727. Da diese Spezialdiskette im Sinne einer  Toolbox konstruiert ist, enthält
  728. sie auch keine fertigen  Programme, sondern nur Demoprogramme. Und
  729. sie  ist   in   allen  Richtungen   erweiterungsfähig.   Ein  paar
  730. Anregungen, wo noch weitere Objekte implementiert werden könnten:
  731.  
  732. - ArrayObj, SListCollection, SListSorted, DListSorted
  733.  
  734. - YesNoWindow, ErrorWindow, InfoWindow, HelpWindow,
  735.   CutAndPasteWindow, EditorWindow
  736.  
  737. - WindowScheduler
  738.  
  739. - StandAloneMenu, PullDownMenu
  740.  
  741. - UserInterFace
  742.  
  743. ...
  744.  
  745. Diese paar  Anregungen genügen,  die  Liste ließe  sich natürlich
  746. endlos fortsetzen,  denn objektorientierte  Programmierung kennt -
  747. wie schon so oft gesagt wurde  - die Möglichkeit der Vererbung und
  748. somit sind die Objekte erweiterbar. Und die Vererbung macht OOP im
  749. Zusammenspiel  mit  Polymorphismus  zu  einem  wirklich  mächtigen
  750. Instrument.
  751.  
  752.                                        Raimond Reichert
  753.  
  754.  
  755.