GFA-Programmierung mit faceVALUE (Teil 3)

center

Nachdem sich die ersten beiden Kursteile auf das Arbeiten mit Dialogfenstern konzentrierten, werden wir diesen Monat den Sprung zu den "Userwindows" wagen. faceVALUE bietet mit diesem Fenstertyp dem Programmierer die Möglichkeit, den Fensterinhalt teilweise oder auch völlig selbst zu gestalten. Bei den Userfenstern gibt es eine klare Arbeitsteilung. Die Engine kümmert sich weiterhin selbständig um Benutzeraktivitäten wie etwa Fenster verschieben, vergrößern oder verkleinern, Scrollpfeile und -balken bewegen oder das Iconify. Ihrer Aufgabe unterliegt es, den Fensterinhalt zu zeichnen und auf Mausklicks und Tastendrücke zu reagieren. Um Ihnen den Einstieg in die Materie zu erleichtern, werden wir zunächst einen einfacher Viewer für Textdateien programmieren. Vorweg möchte ich Sie auf Listing 6 aufmerksam machen. Die Beispiele in diesem Kursteil machen von diesen Routinen Gebrauch. Ihre Funktion sollte leicht klar werden, aber die Arbeitsweise dieser Unterroutinen kann ich hier leider nicht erläutern.

Zur Erzeugung des Programmgerüstes genügt schon die faceVALUE beiliegende Resourcedatei MINIMUM.RSC. Dem Menüeintrag für 'Quit' sollte noch ein Name gegeben werden. Laden Sie die RSC-Datei in faceVALUE ein und öffnen Sie den Main-Dialog (Abbildung 2). Die Routinen, die in der Box 'Library and user' zum Hinzuladen ausgewählt werden müssen, sind in Tabelle 1 zusammengefaßt. Nun kommt der interessante Teil: Die Einstellungen für die Userfenster.

Elementares Verschiedene Userfenster können verschiedene Elemente und Eigenschaften haben. Als Fensterelemente bezeichnet man die Bedienelemente am Fensterrand, also die Titelleiste, die Scrollbalken usw., auch die Infozeile gehört hierzu. Die Fenstereigenschaften beziehen sich auf die Unterschiede, die erst durch das Bedienen der Elemente auftreten. Bei einigen Fenstern bspw. ist der Inhalt immer so groß wie das Fenster selbst (bei einer Analoguhr zum Beispiel), bei anderen kann der Benutzer den Inhalt bei Bedarf scrollen. Damit der Programmierer beim öffnen eines Fensters nicht immer alle Elemente und Eigenschaften explizit angeben muss, werden im rechten Teil des Maindialoges 'User window types' bis zu acht fertige Fenstertypen definiert. Klicken Sie auf den Namen eines Types, um die dem Typ zugeordneten Fensterelemente und Eigenschaften zu verändern (Abbildung 3). Erklärungen zu den Fensterelementen (hier: 'Window attributes') befinden sich in Tabelle 2. Die Eigenschaften werden in faceVALUE in dem Rahmen 'Content' (engl. Inhalt) eingestellt. Auf diese Einstellungen gehe ich näher ein. Das Popup 'Dialog' und die Option 'Background for toolstrip/bar/menu' kommen erst im nächsten Kursteil zur Sprache. Align: Ein Byte-Alignment bewirkt, dass der Benutzer das Fenster horizontal nicht frei positionieren kann, sondern nur in Schritten zu je 8 Pixel. Das führt bei Textausgaben im Fenster mit nichtproportionalen Schriften nicht unerhebliche Geschwindigkeitsvorteile mit sich. Bei Word-Alingnment rastet das Fenster sogar nur alle 16 Pixel ein, wodurch Ausgaben von Pixelgrafiken um ein wenig beschleunigt werden. Vom Word- Alignment sollte man nur selten Gebrauch machen, da es den Benutzer stark einschränkt. Enable blitscolling: Betätigt der Benutzer die Scrollpfeile eines Fensters, wird normalerweise der komplette Fensterinhalt neu gezeichnet. Für die meisten Anwendungen genügt es aber, den bereits sichtbaren Teil des Fensterinhaltes zu verschieben und nur den freiwerdenden Bereich neu zu zeichnen. Bei aktiviertem 'Blitscrolling' geschieht genau das. Voraussetzung ist aber, dass auch die beiden folgenden Buttons angewählt sind. Limit scroll to steps: Der Benutzer kann nicht frei im Fenster umherscrollen, sondern nur in bestimmten Schrittweiten. Die Schrittweite wird später im Programm festgelegt. Limit size to x * step: Das gleiche gilt nun auch für die Fenstergröße. Sinnvoll sind beide Optionen zum Bsp. bei Textfenstern, wo meist nur Zeilenweise gescrollt werden soll, und auch keine halben Zeilen im unteren Bereich sichtbar bleiben sollen. Always redraw when resized: Größenänderungen der Fenster durch den Benutzer bekommt man normalerweise nicht mit, da sich die Enginge um diese Dinge kümmert. In dem oben aufgeführten Beispiel der Analoguhr im Fenster tritt aber der Fall auf, dass sich mit der Fenstergröße auch die Größe der Uhr ändern soll. Um das Fenster für solche Fälle bei Größenänderungen komplett neu zeichnen zu lassen, dient diese Option. Limit max size to content: Beim öffnen eines Fensters muss man der Engine mitteilen wie groß (konkret wieviele Pixel) der Fensterinhalt sein soll. Ist dieser Button angewählt, kann der Benutzer das Fenster nicht größer machen als beim öffnen angegeben wurde. VDI workstation for this window: Durch Anwählen dieser Option bekommt das Fenster einen eigenen Speicher für die Grafikattribute, also bspw. den aktuellen Schriftstil, das aktuelle Füllmuster oder das BOUNDARY. Wenn Sie beim Zeichnen in diesem Fenster später z.Bsp. einen DEFFILL-Befehl ausführen, wirkt er sich nur auf dieses Fenster aus. Stellen Sie für den geplanten Textviewer die Fenstereigenschaften und -attribute entsprechend der Abbildung 3 ein und wählen Sie im Maindialog den so definierten Fenstertyp zur Benutzung in unserem Programm aus. Generieren Sie anschließend das Programmgerüst durch faceVALUE.

Fenster öffne dich

Das öffnen eines Userfensters geschieht mit dem Aufruf von wind_open(). An diese Prozedur werden alle zum öffnen notwendigen Informationen über das Fenster übergeben (Listing 1). Der dritte Parameter enthält den Fenstertyp, der zuvor in faceVALUE definiert wurde. Jeder Fenstertyp hat hierzu eine globale Integervariable erhalten. Der Name der Variablen entspricht dabei dem Namen des Fenstertypes. In unserem Fall heißt die Variable also textwindow%. Bei Fenstern mit Scrollbalken muss die Engine wissen, wie groß der gesamte Fensterinhalt ist. Nur so kann sie die Scrollbalken immer in der Größe dem gerade sichtbaren Ausschnitt anpassen. Mit den Parameter totw& und toth& wird festgelegt, wie groß der Fensterinhalt in seiner gesamten Ausdehnung sein soll. Wenn Sie in dem Fenster bspw. eine Grafik darstellen möchten, die 400x200 Pixel groß ist, dann geben Sie hier diese Werte an. Die hier übergebene Größe hat also nichts mit der wirklichen Größe des Fensters gemein. Die tatsächliche Position und Größe, die das Fenster nach dem öffnen haben soll, wird in x&, y&, w& und h& übergeben. Der Parameter icon& hat die gleiche Funktion wie bei win_open_dialog(). Man kann hier die Baumnummer eines Iconify- Icons angeben. Im Parameter scrlstep& wird die oben angesprochene Schrittweite für das Fensterscrolling und die Größe des gerade sichtbaren Fensterbereiches eingestellt. Was noch bleibt ist der Parameter user_handle&. Den Wert, den Sie hier eintragen, wird von der Engine vorläufig nur gespeichert. Wenn dann später irgendetwas mit einem Fenster geschehen ist, und Sie darauf regieren sollen, gibt die Engine immer den Wert dieses Userhandles mit an. Man sollte damit die Fenster in bestimmte Klassen unterteilen, indem man jeder Klasse einen anderen Wert zuordnet. Wählt man für Textfenster das Userhandle 1, für Grafikfenster das Userhandle 2, so kann man später immer anhand des Userhandles direkt entscheiden, ob nun Text oder Grafik gezeichnet werden muss, oder bspw. ob der Benutzer nur ganze Zeilen oder sogar pixelgenaue Fensterausschnitte markieren kann. Ob und wie Sie diesen Parameter einsetzen ist Ihnen überlassen. (Anm.: Wegen eines Fehlers in der Engine darf hier nie der Wert 0 übergeben werden.) Nach dem Aufruf von win_open() erhalten Sie wie bei win_open_dialog() entweder eine 0 als Fehlermeldung, oder das Handle des Fensters zurück. Das Handle wird u.a. zum Aufruf von win_close() benötigt.

Edvard Munch

Sie erinnern sich? Das ist der Maler, dem das faceVALUE- Gesicht gehört. Keine Angst, zum Pinsel greifen werden wir in diesem Kurs nicht, aber zeichnen müssen wir den Inhalt unserer Userfenster selbst, denn genau das ist der gravierende Unterschied zu den Dialogfenstern. Als erstes benötigt ein Userfenster immer eine Routine zum Zeichnen seines Inhalts. Im nächsten Schritt werden wir für unseren Viewer eine Routine zum Zeichnen von Texten entwickeln.

Fenster haben in der Regel die Eigenschaft, dass man immer nur kleine Ausschnitte der Welt sieht, die sich hinter ihnen verbirgt. Abbildung 4 verdeutlicht, dass auch das Userfenster des Textviewers oft nur kleine Teile des gesamten Textes zeigt. Der komplette sichtbare Ausschnitt lässt sich dabei immer in verschiedene Rechtecke einteilen. In vielen Situationen kommt es nun vor, dass einige Rechtecke des Fensters gezeichnet werden müssen. Dies ist zum Beispiel der Fall, wenn man das Userfenster öffnet, andere oder das eigene Fenster verschiebt, in der Größe ändert oder in den Vordergrund bringt (toppt).
Die faceVALUE-Engine leistet hierbei große Dienste. Sie weiß genau, wann welche Rechtecke welcher Fenster zu zeichnen sind. Ist dies der Fall, verrichtet sie einiges an Vorarbeit und springt anschließend die Routine user_window_content() an. In dieser Prozedur muss der Programmierer dann das Zeichnen des Fensterinhaltes übernehmen.

Das Zeichnen selber läuft genauso ab wie ohne faceVALUE. Sie dürfen alle normalen Grafikbefehle wie TEXT, CIRCLE, PBOX usw. einsetzen. Zu vermeiden sind allerdings die Befehle PUT und GET, gänzlich verboten PRINT und INPUT. Die faceVALUE-Engine schaltet vor dem Aufruf von user_window_content das sog. 'Clipping' ein. Das Clipping bewirkt, dass sich Ihre Zeichenbefehle nur auf das gerade zu zeichnende Rechteck auswirken. Alles was übersteht wird automatisch abgeschnitten und nicht gezeichnet. Der Koordinatenursprung befindet sich zudem nicht mehr in der linken oberen Bildschirmecke, sondern in der linken oberen Ecke des zu zeichnenden Userfensters. Beim Zeichnen entspricht die Koordinate (0 0) der Stelle in Abbildung 3, die mit (wx&wy&) angegeben ist. Wenn der Benutzer den Fensterinhalt mit den Scrollbalken verschieben können soll, dann müssen die Grafikausgaben jeweils um die Offsets off_x& und off_y& verschoben werden. Listing 2 zeigt, wie schnell eine Routine zur Textausgabe zu realisieren ist.

Optimieren

Solange sich der Aufwand in Grenzen hält, kann man in user_window_content immer den kompletten Fensterinhalt zeichnen. Wie aber bereits angesprochen müssen meist nur kleine Teilrechtecke gezeichnet werden. Das Clipping verhindert zwar, dass die Ausgaben über die Rechtecke hinausragen, aber gerade das kostet viel Rechenzeit. Um das zu vermeiden, übergibt die faceVALUE-Engine in user_window_content zusätzlich die Koordinaten des Clippingrechtecks. Man kann dadurch zunächst anhand einer Plausibilitätsabfrage überprüfen, ob ein Objekt wirklich gezeichnet werden muss. Die Koordinaten des Clippingrechtecks (cx& cy&) sind relativ zur linken oberen Bildschirmecke. Durch den Aufruf von @win_get_workarea() können die Koordinaten der Arbeitsfläche des Userfensters (wx& wy&) relativ zur linken oberen Bildschirmecke ermittelt werden. Aus der Koordinatendifferenz und der Addition der Scrolloffsets off_x& und off_y& lässt sich dann schließlich der Teil errechnen, welcher wirklich auf den Fensterinhalt bezogen zu zeichnen ist. Hoffentlich habe ich Sie jetzt nicht abgeschreckt. Anhand der Abbildung 4 ist der Sachverhalt leichter zu verstehen:

x& = (cx&-wx&) + off_x&
y& = (cy&-wy&) + off_y&
w& = cw&
h& = ch&

Im Bezug auf die linke obere Ecke des Textes (grau dargestellt) sind das die Ausmaße des Clippingrechteckes. Es genügt daher, wenn man die Textzeilen von

startzeile& = y& DIV font_h& 

bis

endzeile& = (y&+h&-1) DIV font_h& 

zeichnet (die Zählung der Zeilen beginne bei Zeile 0). In Listing 3 finden Sie die fertige Routine, welche den Bildschirmaufbau von Texten vollständig übernimmt. Wie die Routine dazu genutzt werden kann, in faceVALUE den Dateiviewer zu realisieren, zeigt im Anschluß Listing 4.

Ausblick

Nachdem Sie nun gelernt haben, wie man Ausgaben in Userfenstern macht, werde ich im nächsten Kursteil erklären, wie man auf Mausklicke in die Userfenster und auf Tastendrücke reagieren kann. Bei den bisher eröffneten Einblicken in den Umgang mit Menüs, Dialogen und Userfenstern soll es nicht bleiben. Ich werde unter anderem auf die Mischformen eingehen: Toolbars, Toolstrips und Fenstermenüs. Der letzte noch ausstehende Dialogtyp kommt ebenfalls zur Sprache: die Toolbox, der 'hintergrundbedienbare' Dialog.

Tabelle 1
GDOS fonts & xFSLandere Zeichensätze und Fontselektoraufruf
change window sizeGröße von Userfenstern ändern
keyb. scroll userw.per Cursortasten scrollbare Userfenster
Drag and DropMultiTOS-Drag'n Drop-Unterstützung
commandlineKommandozeile abfragen
clipboard supportGEM-Klemmbrettunterstützung
Tabelle 2
titleTitelzeile mit Text
closerSchließbutton
fullerButton für volle Fenstergröße
moverButton zum Verschieben des Fensters (normalerweise ebenfalls die Titelzeile)
info lineInfozeile unter der Titelzeile
sizerButton, um die Größe des Fensters zu Ändern
vertical scroll arrowssenkrechte Scrollpfeile
vertical slidersenkrechter Sliderbalken
horisontal scroll arrowswaagerechte Scrollpfeile
horisontal sliderwaagerechter Sliderbalken
smaller (iconify)Iconifybutton
Listings: listing1.lst listing2.lst listing3.lst listing4.lst listing5.lst Programme: Fileviewer.zip (36 KB)
Holger Herzog
Aus: ST-Computer 04 / 1997, Seite 42

Links

Copyright-Bestimmungen: siehe Über diese Seite