|
Benutzerhandbuch |
|
|
Kapitel 5
Beispiele
·Zahlen raten
·Ein eigenständiges Workbench-Programm
·Ein graphisches Beispiel
·Menüs & File-Requester
·String-Gadgets
·Prop-Gadgets
·Telefonbuch-Datenbank
·Verwaltung von Betriebssytem-Listen
·Primzahlgenerator
In diesem Kapitel werden die in den vorhergehenden Kapiteln beschriebenen Konzepte anhand zahlreicher Beispiele erläutert.
Unerfahrene Programmierer sollten auf jeden Fall zunächst die Beispiele in Kapitel 2 ausprobieren, bevor Sie sich an diese heranwagen.
Zahlen raten
Im folgenden kleinen Programm denkt sich der Rechner eine Zahl aus und der Benutzer muß versuchen, Sie in zehn versuchen zu raten.
NPrint "Ich habe mir eine Zahl zwischen 0 und 100 ausgedacht"
NPrint "Ich gebe dir zehn Versuche, sie zu raten:"
a=Rnd(100)
n=1
Repeat
Print n, ". Versuch ?"
b=Edit(10)
If b=a Then NPrint "Glück gehabt":Goto finish
If b<a Then NPrint "Zu klein"
If b>a Then NPrint "Zu gross"
n+1
Until n=11
NPrint "10 Versuche, das war's!"
finish:
NPrint "Mausknopf drücken um das Programm zu beenden."
MouseWait
Es wird zunächst recht schwierig sein, die Zahl zu raten, weil der Zufallszahlengenerator standardmäßig keine ganze Zahl erzeugt, sondern auch Nachkommastellen.
Ändern Sie daher die Zeile a=Rnd(100) entweder in a.w=Rnd(100) oder a=Int(Rnd(100)).
Der Zusatz .w steht für Word und hat zur Folge, daß die Variable a jetzt ganzzahlig (im Bereich -32768 bis +32767) ist. Bei der zweiten angegebenen Möglichkeit ist a zwar immer noch vom Typ Quick, durch den Aufruf von Int() wird der Nachkommateil der Zahl jedoch abgeschnitten.
Immer wenn in Blitz2 eine Variable ohne .typ-Suffix angegeben wird, wird automatisch der Quick-Typ angenommen. Der Wertebereich liegt zwischen -32768 und +32767 bei einer Genauigkeit von 1/65536. Siehe auch den Abschnitt über Datentypen.
DEFTYPE .w ; alle Variablen ohne Suffix sind Word
Ist eine Variable einmal vereinbart worden, ist ihr Typ damit festgelegt und eine Angabe des .typ-Zusatzes ist bei weiteren Zugriffen nicht mehr nötig.
Im Gegensatz zu anderen BASIC-Versionen fügt das Print-Kommando nicht automatisch einen Zeilenvorschub an das Ende des ausgegebenen Textes an. Wenn dieses gewünscht wird, ist der NPrint-Befehl zu verwenden.
Die Funktion Edit() ersetzt das ältere Kommando 'input'. Ebenso wird das Semikolon statt des Befehls REM für Kommentare verwendet und es besitzt nicht mehr die alte Bedeutung in Zusammenhang mit dem Print-Befehl.
Ein eigenständiges (standalone) WorkBench-Programm
Aus dem Rate-Programm kann ein eigenständiges Programm mit zugehörigem Symbol(Icon) gemacht werden, daß von der Workbench aus gestartet werden kann.
Die folgenden Zeilen sind am Anfang des Programmcodes einzufügen
Die Texte hinter dem Semikolon sind, wie bereits erwähnt, Kommentare.
;
; Zahlen-Rate Programm
;
WBStartup ; noetig um Prog. von der Workbench aus zu starten
FindScreen 0 ; vorderste Intuition Screen holen
;
Window 0,0,0,320,210,$1000,"Hello World",1,2
Wenn Sie das Programm jetzt übersetzen und laufen lassen, wird die Ein- und Ausgabe über das Window erledigt, anstatt mit der Kommandozeile.
Es sollte noch folgende Änderung der Zeile b=Edit(10) vorgenommen werden:
b=Val(Edit$(10))
Dadurch wird die standardmäßige Ausgabe des 0-Zeichens bei der Window-Version von Edit() unterdrückt.
Schalten Sie jetzt die Option Create Executable Icon im Editor-Menü an und wählen Sie Create Executable oder drücken Sie das Kürzel Amiga-E.
Geben Sie dann einen Namen für das Programm ein. Sie haben soeben ihr erstes eigenständiges Workbench-Programm erzeugt. Dies können Sie jetzt starten, indem Sie auf das zugehörige Icon klicken.
Ein graphisches Beispiel
Das folgende Programm öffnet zunächst eine eigene Screen und zeichnet dann eine Rosette, also eine Figur, bei der alle Punkte eines Kreises durch Linien verbunden werden.
;
; Rosetten-Beispiel
;
n=20
NEWTYPE .pt
x.w:y
End NEWTYPE
Dim p.pt(n)
For i=0 To n-1
p(i)\x=320+Sin(2*i*Pi/n)*319
p(i)\y=256+Cos(2*i*Pi/n)*255
Next
Screen 0,25 ;einfarbige interlace screen anfordern
ScreensBitMap 0,0
For i1=0 To n-2
For i2=i1+1 To n-1
Line p(i1)\x,p(i1)\y,p(i2)\x,p(i2)\y,1
Next
Next
MouseWait
Der mit NewType definierte Datentyp .pt besitzt zwei Elemente, x und y. Dadurch brauchen nicht zwei Felder x.w(n) und y.w(n) angelegt zu werden, sondern nur ein Feld des Typs .pt, das dieselbe Information enthält.
Die einzelnen Elemente des NewType werden mit dem Backslash-Zeichen "\" erreicht.
In der ersten For...Next-Schleife werden zunächst die Punkte des Kreises berechnet.
Mit dem Befehl ScreenBitMap kann anschließend direkt auf die Screen mit den Befehlen Plot, Line, Box und Circle zugegriffen werden. Programme, die Windows benutzen, sollten diese Methode nicht anwenden, sondern zum Zeichnen die Befehle WPlot, Wline, WBox und WCircle verwenden.
Menüs und File-Requester
Das folgende Beispiel demonstriert den Gebrauch von Menüs und File-Requestern. Es erzeugt eine Screen und ein Window, bringt eine Menüleiste an und je nachdem, was der Benutzer auswählt, erscheint ein File-Requester oder das Programm wird beendet.
;
; Ein einfaches Beispiel für einen File Requester
;
Screen 0,11,"Ein Menü auswählen" ; intuition screen öffnen
MenuTitle 0,0,"Projekt" ; Menüliste anlegen
MenuItem 0,0,0,0,"Laden ","L"
MenuItem 0,0,0,1,"Sichern ","S"
MenuItem 0,0,0,2,"Quit ","Q"
MaxLen path$=192 ;MUSS angegeben werden, bevor der Requester benutzt wird
MaxLen name$=192
; Ein BACKDROP (d.h. unsichtbares) Window erzeugen
Window 0,0,0,320,200,$1900,"",1,2
WLocate 0,20 ; Cursor in die linke obere Ecke
SetMenu 0 ;Menü mit dem Fenster verbinden
Repeat
Select WaitEvent
Case 256 ; ein Menü-Event!
Select ItemHit
Case 0 ; Eintrag 0: Laden
p$=FileRequest$("Datei laden",path$,name$)
NPrint "Jetzt wird ",p$, "geladen"
Case 1 ; Eintrag 1: Sichern
p$=FileRequest$("Datei sichern", path$, name$)
NPrint "Jetzt wird ",p$, "gesichert"
Case 2 ;Eintrag 2:Quit
End
End Select
End Select
Forever
Mit dem Befehl MaxLen wird ein Speicherbereich für eine Stringvariable angefordert. Dies ist notwendig, damit die beiden Stringvariablen, für den File-Requester genügend Platz für die Eingabe haben.
Die Menüs, die mit MenuTitle und MenuItem erzeugt wurden, werden mit dem Befehl SetMenu mit dem Window verbunden.
Die Struktur Select...Case...EndSelect eignet sich am besten, um auf Ereignisse, die von außen (in diesem Fall vom Benutzer) kommen zu reagieren. Wenn der Benutzer ein Menü auswählt, ein Window schließt oder auf einen Knopf klickt, findet ein Ereignis statt und eine entsprechende Nachricht wird an das Programm gesendet. Ein Programm sollte mit dem Befehl WaitEvent auf ein Ereignis warten. Dadurch 'schläft' das Programm solange, bis der Benutzer etwas eingibt. In einer Multi-Tasking-Umgebung können dann in der Zwischenzeit andere Programme weiterarbeiten. Ein Programm, das auf ein Ereignis wartet, belastet das System nicht.
Wurde ein Event empfangen, liefert WaitEvent eine Kennung für die Art des Events zurück. Ein Menü-Ereignis liefert z.B. den Wert 256 ($100 hex) zurück, ein Close Winwow Ereignis liefert 512 ($200 hex). Auf Seite 25-5 <<< ? >>> des Referenzhandbuchs befindet sich eine vollständige Liste der Events.
String Gadgets
String Gadgets sind Eingabefelder, in die der Benutzer Texteingaben mit der Tastatur vornehmen kann. Im folgenden Beispiel werden 3 Eingabefelder für dezimale, hexadezimale und binäre Ein- und Ausgabe erzeugt.
Wenn der Benutzer eine Zahl in eines der Gadgets einträgt, erhält das Programm eine Gadgetup-Nachricht. Die Funktion GadgetHit liefert dann die Nummer des Gadgets, in dem die Eingabe erfolgte. Anschließend konvertiert das Programm die Zahl in die anderen beiden Zahlensysteme und gibt das Ergebnis in allen Gadgets aus.
Mit dem Befehl ActivateString wird erreicht, daß der Benutzer nicht erst mit der Maus auf eines der Gadgets klicken muß, bevor etwas eingegeben werden kann.
;
; Dezimal, Hex, Binär Konverter
;
FindScreen 0
StringGadget 0,64,12,0,0,18,144
StringGadget 0,64,26,0,1,18,144
StringGadget 0,64,40,0,2,18,144
Window 0,100,50,220,56,$1008,"BASIS KONVERTER",1,2,0
WLocate 2,04:Print "DEZIMAL"
WLocate 2,18:Print " HEX$"
WLocate 2,32:Print "BINÄR%"
DEFTYPE.l value
Repeat
ev.l=WaitEvent
If ev=$40 ;Gadget up Event
Select GadgetHit
Case 0
value=Val(StringText$(0,0))
Case 1
r$=UCase$(StringText$(0,1))
value=0:i=Len(r$):b=1
While i>0
a=Asc(Mid$(r$,i,1))
If a>65 Then a-55 Else a-48
value+a*b
i-1:b*16
Wend
Case 2
r$=StringText$(0,2)
value=0:i=Len(r$):b=1
While i>0
a=Asc(Mid$(r$,i,1))-48
value+a*b
i-1:b*2
Wend
End Select
ActivateString 0,GadgetHit
SetString 0,0,Str$(value)
SetString 0,1,Right$(Hex$(value),4)
SetString 0,2,Right$(Bin$(value),16)
Redraw 0,0:Redraw 0,1:Redraw 0,2
EndIf
Until ev=$200
Prop Gadgets
Das folgende Beispielprogramm erzeugt einen einfachen Requester für eine RGB-Palette, mit dem die Bildschirmfarben eingestellt werden können. Prop Gadgets sind Schieberegler, die in diesem Fall für die Einstellung der Rot-, Grün- und Blaukomponenete des aktuellen Farbregisters dienen.
Die 32 Farbregister werden durch 32 Text Gadgets repräsentiert. Die Farbe der einzelnen Gadgets wird mit dem Befehl GadgetPen festgelegt. Dies geschieht bevor die Gadgets zu der Objektliste hinzugefügt werden. Der Befehl GadgetJam führt dazu, daß die beiden Leerzeichen als farbige Blöcke dargestellt werden.
;
; Einfache Farbpalette
;
FindScreen 0
For p=0 To 2
PropGadget 0,p*22+8,14,128,p,16,54
Next
For c=0 To 31
GadgetJam 1:GadgetPens 0,c
x=c AND 7:y=Int(c/8)
TextGadget 0,x*28+72,14+y*14,32,3+c," " ;<-2 Leerzeichen
Next
Window 0,100,50,300,72,$100A,"FARB-PALETTE",1,2,0
cc=0:Toggle 0,3+cc,On:Redraw 0,3+cc
Repeat
SetVProp 0,0,1-Red(cc)/15,1/16
SetVProp 0,1,1-Green(cc)/15,1/16
SetVProp 0,2,1-Blue(cc)/15,1/16
Redraw 0,0:Redraw 0,1:Redraw 0,2
ev.l=WaitEvent
If ev=$40 AND GadgetHit>2
Toggle 0,3+cc,On:Redraw 0,3+cc
cc=GadgetHit-3
Toggle 0,3+cc,On:Redraw 0,3+cc
EndIf
If (ev=$20 OR ev=$40) AND GadgetHit<3
r.b=VPropPot(0,0)*16
g.b=VPropPot(0,1)*16
b.b=VPropPot(0,2)*16
RGB cc,15-r,15-g,15-b
EndIf
Until ev=$200
Datenbank-Anwendung
Es folgt ein Beispiel für ein einfaches Datenbank-Programm, eine Adressverwaltung. Es verwaltet eine Liste mit Namen, Telefonnummern und Adressen.
Die Definition der Bedienoberfläche kann entweder so eingetippt werden, wie sie weiter unten gedruckt ist, oder sie kann mit IntuiTools erstellt werden.
Wenn eine Datei mit dem Namen phonebook.data existiert, wird sie eingelesen. Es wird eine Liste daraus aufgebaut, deren Einträge aus jeweils 4 Strings bestehen, die im NewType definiert sind.
Durch die Verwendung einer Liste statt eines einfachen Feldes, wird klar, daß die Einträge in einer gewissen Beziehung zueinander stehen. Blitz2 verwaltet einen internen Zeiger auf das aktuelle Listenelement, der mit einer Reihe von Listenbefehlen gesetzt und abgefragt werden kann.
;
; Telefonbuch-Programm
;
FindScreen 0
; Die folgende Beschreibung wird von ram:t gelesen und wurde mit
; IntuiTools erstellt
Borders On:BorderPens 1,2:Borders 4,2
StringGadget 0,72,12,0,1,40,239
StringGadget 0,72,27,0,2,40,239
StringGadget 0,72,43,0,3,40,239
StringGadget 0,72,59,0,4,40,239
GadgetJam 0:GadgetPens 1,0
TextGadget 0,8,75,0,10,"NEUER EINTRAG"
TextGadget 0,97,75,0,11,"|<"
TextGadget 0,129,75,0,12,"<<"
TextGadget 0,161,75,0,13,">>"
TextGadget 0,193,75,0,14,">|"
TextGadget 0,226,75,0,15,"DIAL"
TextGadget 0,270,75,0,16,"LABEL"
SizeLimits 32,32,-1,-1
Window 0,0,24,331,91,$100E,"MEIN TELEFONBUCH",1,2,0
WLocate 2,19:WJam 0:WColour 1,0
Print "Adresse"
WLocate 19,50
Print "Telefon"
WLocate 27,3
Print "Name"
; nun beginnt die Eingabe...
#num=4 ;4 strings für jede Person
NEWTYPE .person
info$[#num]
End NEWTYPE
Dim List people.person(200)
USEPATH people()
; Daten aus bestehendem sequentiellen File einlesen
If ReadFile (0,"phonebook.data")
FileInput 0
While NOT Eof(0)
If AddItem(people())
For i=0 To #num-1:\info[i]=Edit$(128):Next
EndIf
Wend
EndIf
ResetList people()
; Wenn Liste leer, ein Listenelement einfügen
If NOT NextItem(people()) Then AddItem people()
refresh:
ref=0
For i=0 To #num-1
SetString 0,i+1,\info[i]:Redraw 0,i+1
Next
ActivateString 0,1:VWait 5
Repeat
ev.l=WaitEvent
;
If ev=$200 ; Fenster schliessen
Gosub update
If WriteFile (0,"phonebook.data") ; Daten in File schreiben
FileOutput 0
ResetList people()
While NextItem(people())
For i=0 To #num-1:NPrint \info[i]:Next
Wend
CloseFile 0
EndIf
EndIf
;
If ev=64
If GadgetHit=#num Then ActivateString 0,1
If GadgetHit<#num Then ActivateString 0,GadgetHit+1
Select GadgetHit
Case 10
Gosub update:If AddItem(people()) Then ref=1
Case 11
Gosub update:If FirstItem(people()) Then ref=1
Case 12
Gosub update:If PrevItem(people()) Then ref=1
Case 13
Gosub update:If NextItem(people()) Then ref=1
Case 14
Gosub update:If LastItem(people()) Then ref=1
End Select
EndIf
Until ref=1
Goto refresh
update:
For i=0 To #num-1:\info[i]=StringText$(0,i+1):Next:Return
Verwaltung von Betriebssystem-Listen
Das folgende Programm erläutert den Zugriff auf Strukturen des Betriebssystems. Dieses Programm benötigt die Datei AmigaLibs.res in der Blitz2-Umgebung. Hierfür wählen Sie die Compiler Options aus dem Menü, klicken in das Feld Residents und geben den Namen AmigaLibs.res ein. Möglicherweise wird ein Pfadname benötigt. Die Datei AmigaLIbs befindet sich im Verzeichnis "Residents" der Blitz2 Programmdiskette.
Wenn Sie jetzt View Types im Compiler-Menü auswählen, erscheint eine Liste aller Strukturen, die vom Amiga-Betriebssystem verwendet werden.
In der ersten Programmzeile wird eine Variable exec als Zeiger vom Typ ExecBase definiert. Da der Amiga die Adresse der Listen in der Speicheradresse 4 hält, kann mit dem Befehl Peek.l(4) der 4 Byte lange Wert vom Speicher in unsere Zeigervariable gelesen werden.
Da die Variable exec als Zeiger auf eine ExecBase-Struktur definiert wurde, kann jetzt mit dem Backslash auf jedes Element der Struktur mit dessen Namen zugegriffen werden. Die Namen der Strukturelemente können mit Hilfe des ViewType-Menüs angesehen werden, wenn Sie den Namen ExecType (Großschreibung beachten) eingeben.
Anschließend wird eine weitere Pointervariable angelegt (diesmal vom Typ .List), die auf ein Listenelement der Exec-Struktur zeigt.
Alle Exec-Listen bestehen aus Knoten (nodes). Der erste Knoten repräsentiert immer den Listenkopf, danach folgen die Daten.
In der dritten Zeile wird die Variable mynode als Zeiger vom Typ .Node definiert und zeigt auf den ersten Knoten der Liste.
In der Schleife wird die Liste dann solange abgearbeitet, bis der Zeiger auf den Nachfolger (successor) 0 ist. Damit ist wieder der Anfang der Liste erreicht.
Der Befehl Peek$ liest ASCII-Zeichen aus dem Speicher, bis eine Null erreicht wird. Dies ist sehr nützlich um Strings, die in C-Notation abgelegt sind (C-Strings werden mit einem Null-Byte beendet), wie *In_Name, einzulesen.
Als letztes wird dem Pointer mynode die Adresse des eigenen Nachfolgers zugewiesen.
;
; Exec-Listenverwaltung
;
*exec.ExecBase=Peek.l(4)
*mylist.List=*exec\LibList
*mynode.Node=*mylist\lh_Head
While *mynode\ln_Succ
a$=Peek$(*mynode\ln_Name)
NPrint a$
*mynode=*mynode\ln_Succ
Wend
MouseWait
Primzahlgenerator
Im letzten Beispiel wird eine Liste aller Primzahlen von 2 bis zu einer Höchstzahl, die vom Benutzer eingegeben wird, berechnet. Die Primzahlen werden in Form einer Blitz2-Liste verwaltet.
Das Programm beginnt mit dem Einlesen der Höchstgrenze mit Hilfe der Standard Eingabe- und Ausgabekanäle und des Befehls Edit(), der numerischen Variante von Edit$().
Die Arbeitsschleife While..Wend wird solange durchlaufen, bis der Höchstwert erreicht ist. Der Algorithmus besteht lediglich darin, die nächste ganze Zahl zu nehmen und mit der Liste der zuvor erzeugten Primzahlen zu vergleichen, bis eine ganzzahlige Division möglich ist oder bis die Prüfgrenze erreicht wurde (dies ist die Wurzel der in Frage kommenden Zahl).
Wurde kein ganzzahliger Teiler gefunden, wird die neue Primzahl ausgedruckt und an das Ende der Liste angefügt.
Print "Höchstwert eingeben " ; Grenzwert des Programms
v=Edit(80) ; numerische Eingabe
If v=0 Then End ; Abbruch bei 0
tab.w=0:tot.w=0 ; Zähler rücksetzen
Dim List primes(v) ; Primzahl-Liste anlegen
p=2 ; 2 ist der erste Eintrag
AddItem primes()
primes()=p
While p<v ; Schleife bis Ende erreicht ist
p+1 ; p erhöhen
flag=1 ; flag setzen
d=0
q=Sqr(p) ; Suchgrenze festlegen
ResetList primes() ; Schleife über die Liste
While NextItem(primes()) AND d<q AND flag
d=primes()
flag=p MOD d
Wend
If flag<>0 ; gefunden: ausgeben und in Liste eintragen
Print p,Chr$(9) ;chr$(9) ist der TAB
tab+1:tot+1
If tab=10 Then NPrint "":tab=0
AddLast primes()
primes()=p
EndIf
Wend
NPrint Chr$(10)+"Habe ",tot," Primzahlen zwischen 2 & ",v, "gefunden"
NPrint "Beenden mit linkem Mausknopf"
MouseWait
|
|
|
|
|