[Monkey] GUI Tutorial

Übersicht Andere Programmiersprachen FAQs und Tutorials

Neue Antwort erstellen

Midimaster

Betreff: GUI Tutorial

BeitragFr, Aug 03, 2012 10:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Dieses Tutorial wird darstellen, wie man eine GUI in Monkey erstellt. Es geht nicht so sehr um den optischen Teil, sondern mehr um die Logik, wie man mit Klassen und Listen an eine solche Frage herangeht. Außerdem wird die GUI auflösungsunabhängig für die verschiedenen Display sein.

Hier mal ein erster Blick drauf. Wie man sieht geht es in Richtung Android GUI:

user posted image

Theoretisch lässt sich das Wissen auch auf Bmax übertragen. Bis auf wenige Besonderheiten wird der Code auf beiden Targets ausführbar bleiben. Dies ist kein Anfänger Tutorial. Es geht nicht um die Verwendung von GUIs, sondern um die Programmierung einer neuen GUI.

Wie bei allen Midimaster-Tutorials werde ich die Kapitel jeweils in eigene Postings stecken und bitte deshalb die Admins, mir ein Mehrfach-Posting zu erlauben. Ebenso soll die Abfolge der Kapitel nicht durch Fragen und Kommentare gestört werden, daher bitte ich alle Antworten hier zu posten: https://www.blitzforum.de/foru...hp?t=33457 . Fragen von Hilfesuchenden bitte hierhin https://www.blitzforum.de/forum/viewforum.php?f=50 und auf keinen Fall in diesen Thread.

Achtung: Das Tutorial wird derzeit überarbeitet. Bisher habe ich nur Kapitel 1 bis 3 aktualisiert. Die Kapitel 4 bis 6 passen deshalb nicht mehr richtig dazu. Geplante Fertigstellung Ende Juli 2013


Die Kapitel:

Kapitel 1: Alles Gadget oder was?

Kapitel 2: Mütter und Kinder

Kapitel 3: Touch Down


Kapitel 4: Etwas Styling

Kapitel 5: Scrolling

Kapitel 6: Texteingabe
  • Zuletzt bearbeitet von Midimaster am Do, Jul 04, 2013 0:46, insgesamt 14-mal bearbeitet

Midimaster

Betreff: Kapitel 1: Alles Gadget, oder was?

BeitragFr, Aug 03, 2012 12:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Kapitel 1: Alles Gadget, oder was?


Zunächst der übliche Monkey-Überbau:

BlitzMax: [AUSKLAPPEN]
Strict
Import mojo

Class MyGame Extends App
Method OnCreate%()
SetUpdateRate 15
Return 0
End

Method OnUpdate%()
Return 0
End

Method OnRender%()
Cls 0,111,0
Gadget.Draw
Return 0
End
End

Function Main%()
New MyGame()
Return 0
End

Class Gadget

Function Draw%()
Print "male GUI"
Return 0
End

Function Check%()
Return 0
End
End


So fang ich üblicherweise immer Programme an. Es gibt schon die Klasse Gadget, die später die GUI darstellt, es gibt dort auch schon Funktionen, die vom Hauptprogramm MyGame aufgerufen werden, aber die Funktionen sind kompett inhaltslos. Der Vorteil eines solchen Aufbaus ist, dass das Programm schon läuft! Späteres Hinzufügen von Code kann also immer gleich getestet werden: "Wenn das Programm nicht anläuft muss es an dem neuen Code liegen.".

Die Elemente der GUI selbst werden aus immer dem gleichen Typen bestehen. Wir nennen es Gadget. Es kann Frame und Label sein, Button und Ceckbox, Scrollfenster und Silder und, und und....

Jedes dieser Elemente hat eine eindeutige Variable Typ. Daran unterscheidet dann die Arbeitweise des Gadget. Außerdem die Üblichen Werte wie X, Y, Breite, Höhe, ... .

Ein Element kennt immer seine Mutter, seine Kinder tragen sich später in die Children-Liste. So kennt es später also auch seine Kinder.

Daraus ergeben sich die ersten Fields, die unser Gadget haben muss:


BlitzMax: [AUSKLAPPEN]
Strict
Import mojo

Class MyGame Extends App

Field Window:Gadget, Top:Gadget

Method OnCreate%()
SetUpdateRate 10
Window = Gadget.Create(0,0,360,480,0) ' Mutter aller Fenster
Top = Gadget.Create(2,2,356,56,1,Window)
Return 0
End

Method OnUpdate%()
If KeyHit(KEY_CLOSE) Or KeyHit(KEY_ESCAPE) Then Error ""
Return 0
End

Method OnRender%()
Gadget.Draw
Return 0
End
End

Function Main%()
New MyGame
Return 0
End

Class Gadget
Global Mother:Gadget
Field X%,Y%,B%,H%,Text$,Typ%
Field Parent:Gadget, Visible%, Enable%
Field Children:List<Gadget>= New List <Gadget>

Function Create:Gadget(X%,Y%,B%,H%,Typ%,Eltern:Gadget=Null,Text$="")
Local loc:Gadget=New Gadget()
loc.X=X
loc.Y=Y
loc.B=B
loc.H=H
loc.Typ=Typ
loc.Text=Text
loc.Visible=True
loc.Enable=True
If Eltern=Null
loc.Parent=Null
Mother=loc
Else
loc.Parent=Eltern
Eltern.Children.AddLast loc
EndIf
Return loc
End



Function Draw%()
Print "male GUI"
Return 0
End


Function Check%()
Return 0
End
End



Wie ihr seht bleibt alles noch sehr abstrakt und völlig ohne Malen. Dies werde ich erst in Kapitel 2 zeigen.

Unsere GUI benötigt ein "Mutter"-Fenster. Weitere Gadgets sind Kinder oder Enkel dieser Mutter .
  • Zuletzt bearbeitet von Midimaster am So, Jun 16, 2013 15:33, insgesamt 4-mal bearbeitet

Midimaster

Betreff: Kapitel 2: Mütter und Kinder

BeitragSa, Aug 04, 2012 1:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Kapitel 2: Mütter und Kinder

Eine der zentralen Eigenschaften der GUI ist es, zu wissen wo und ob etwas hingemalt werden muss und was der User gerade auswählt. Hier hilft das Mutter-Kinder-Prinzip, das jedes Gadget genau in einen Container unterbringt. Der Container wiederum kann viele Elemente enthalten. Diese Elemente können selbst wieder Container für weitere Gadgets sein. Dies entspricht dem Vorbild einer "Mutter", die viele Kinder haben kann, die wiederum Kinder haben können. Aber jedes Kind hat immer nur eine Mutter.

So kann man sich z.b. ein Scroll-Fenster als rechteckige Mutter vorstellen, die zwei Kinder nebeneinander hat: den rechteckigen sichtbaren Image-Bereich und ein rechteckiges Scroll-Element.Der sichtbare Image-Bereich ist wiederum Mutter des Bildes, das viel größer als der sichtbare Bereich sein kann. Das Scroll-Element ist wiederum Mutter für den rechteckigen Slider, der sich darin bewegen kann. So lassen sich auch scheinbar komplexe Gadget letzendlich in viele kleine nebeneinander oder ineinanderliegende Rechtecke darstellen.

Sehen wir uns zunächst an, wie man die Gadgets zeichnet:

Es beginnt immer bei der Mutter aller Mütter. Dem einzigen Gadget, dass selbst keine Mutter hat. Oft wird es "Fenster" genannt.

BlitzMax: [AUSKLAPPEN]
Function Draw%()
Mother.DrawOne(0,0,0,0,DeviceWidth(),DeviceHeight())
Return 0
End


Die Funktion Gadget.Draw() startet eigentlich nur das Malen der ÜberMutter, die dann rekursiv auch ihre Töchter malen wird. Die Parameter die dabei übergeben werden sind die Koordinaten und Malgrenzen des Bildschirms. Der Scissor() ist eine Funktion von Monkey, die ähnlich dem SetViewPort() aus BMax den Malbereich auf ein Rechteckauschnitt beschränkt. Zunächst steht er für die Übermutter auf den Grenzen des Bildschirms. Später werden die Gadgets ihre eigenen Grenzen so an die Kinder weiterreichen.

Das Malen erfolgt in der Methode Gadget.DrawOne()

BlitzMax: [AUSKLAPPEN]
Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
If Visible=False Then Return 0
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0
SetScissor sX , sY , (sX2-sX) , (sY2-sY)
' hier das eigentliche Malen:
SetFarbe Typ
DrawRect X, Y,B,H
' und endet wieder
PushMatrix
Translate X,Y
For Local loc:Gadget = EachIn Children
loc.DrawOne sX, sY, sX2, sY2
Next
PopMatrix
Return 0
End

Ist das Gadget nicht visible wird gleich abgebrochen und so auch die Kinder erst gar nicht gemalt.

Danach werden zu den eigenen Koordinaten X Y die Koordinaten der Mutter offX offY addiert.

Nun wird der Scissor auf seine zukünftigen Grenzen eigestellt. Sind die Ausmaße des Gadget enger als der bisherige Scissor, werden diese Aumaße als neue Grenzen des Scissors festgesetzt:
BlitzMax: [AUSKLAPPEN]
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H

If (sX2<sX) Or (sY2<sY) Then Return 0

Die letzt Zeile erzwingt einen Abbruch des Malens, wenn der Scissor jetzt eine Breite oder Höhe unter Null haben sollte. Dies wird immer dann der Fall sein, wenn das Gadget außerhalb des sichtbaren Bereichs liegt. Auch die Kinder werden so nicht mehr gemalt.

Schließlich wird gemalt. Während der Erprobungsphase genügt es hier ein farbiges Rechteck zu zeichnen. Wenn des damit funktioniert wird es später auch mit aufwendigen Themes gelingen.

Nun kommt der interessanteste Teil. Das Gadget ruft seine Kinder auf und übergibt als Parameter seine eigenem X Y Koordinaten, sowie den soeben neu ausgerechneten Scissor:
BlitzMax: [AUSKLAPPEN]
For Local loc:Gadget = EachIn Children
loc.DrawOne offX, offY, sX, sY , sX2, sY2
Next


Nachzutragen bleibt nur noch eine kleine Funktion SetFarbe(), die während der Simulation zur Unterscheidung der Gadgets dient. Sie legt für die Gadgets unterschiedliche Farben fest. Später könnte man hier komplette Themes und Styles festlegen.

Und so sieht nun unsere GUI momentan aus:

BlitzMax: [AUSKLAPPEN]
Strict
Import mojo

Class MyGame Extends App

Global Window:Gadget,Top:Gadget, Button1:Gadget, Button2:Gadget, Weiss:Gadget

Method OnCreate%()
SetUpdateRate 10
Window = Gadget.Create(0,0,360,480,0,Null) ' Mutter aller Fenster
Top = Gadget.Create (30,30,360,150,2,Window) ' graues Top feld
Weiss = Gadget.Create( 10,90, 200,40,1,Top) ' weißer Innenbereich
Button1= Gadget.Create (5,5, 90,50,3,Weiss) ' rosa Button im weißen
Button2= Gadget.Create (5,5, 90,50,3,Top) ' rosa Button im grauen
Return 0
End

Method OnUpdate%()
If KeyHit(KEY_CLOSE) Or KeyHit(KEY_ESCAPE) Then Error ""
Return 0
End

Method OnRender%()
Cls 0,111,0
Local Zeit%=MilliSecs()
Gadget.Draw
Print "Zeit=" + (MilliSecs()-Zeit)
Return 0
End
End



Function Main%()
New MyGame
Return 0
End



Class Gadget
Global Mother:Gadget
Field X%,Y%,B%,H%,Text$,Typ%
Field Parent:Gadget, Visible%, Enable%
Field Children:List<Gadget>= New List <Gadget>

Function Create:Gadget(X%,Y%,B%,H%,Typ%,Eltern:Gadget=Null,Text$="")
Local loc:Gadget=New Gadget()
loc.X=X
loc.Y=Y
loc.B=B
loc.H=H
loc.Typ=Typ
loc.Text=Text
loc.Visible=True
loc.Enable=True
If Eltern=Null
loc.Parent=Null
Mother=loc
Else
loc.Parent=Eltern
Eltern.Children.AddLast loc
EndIf
Return loc
End


Function Draw%()
Mother.DrawOne(0,0,0,0,DeviceWidth(),DeviceHeight())
Return 0
End



Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
If Visible=False Then Return 0
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0
SetScissor sX , sY , (sX2-sX) , (sY2-sY)
' hier das eigentliche Malen:
SetFarbe Typ
DrawRect X, Y,B,H
' und endet wieder
PushMatrix
Translate X,Y
For Local loc:Gadget = EachIn Children
loc.DrawOne sX, sY, sX2, sY2
Next
PopMatrix
Return 0
End



Function Check%()
Return 0
End
End






Function SetFarbe:Void(FarbTon%)
Select FarbTon
Case 0
SetColor 1,1,1
Case 1
SetColor 222,222,222
Case 2
SetColor 111,111,111
Case 3
SetColor 200,100,100
End Select
End Function




In der Praxis
Hier einige Experimente, die Ihr jetzt schon mit diesem Teil ausprobieren könnt. Dazu müsst ihr im Code siehe oben immer nur die Class MyGame Extends App durch die Beispiele ersetzen.



Mutter und Tochter

wenn die Mutter bewegt wird geht die Tochter mit:
BlitzMax: [AUSKLAPPEN]
Class MyGame Extends App

Global Window:Gadget,Top:Gadget, Button1:Gadget, Button2:Gadget, Weiss:Gadget

Method OnCreate%()
SetUpdateRate 10
Window = Gadget.Create(0,0,360,480,0,Null) ' Mutter aller Fenster
Top = Gadget.Create (30,30,360,150,2,Window) ' graues Top feld
Button1= Gadget.Create (5,5, 90,50,3,Top) ' rosa Button im grauen
Return 0
End

Method OnUpdate%()
If KeyHit(KEY_CLOSE) Or KeyHit(KEY_ESCAPE) Then Error ""
Top.X=Top.X+1
Return 0
End

Method OnRender%()
Cls 0,111,0
Local Zeit%=MilliSecs()
Gadget.Draw
Print "Zeit=" + (MilliSecs()-Zeit)
Return 0
End
End




Fenstergrenzen

Als Alternative bewegt Ihr mal die Tochter. Tatsächlich sorgt die Gadget.Draw() bereits dafür, dass die Tochter nicht über die Mutter hinausgemalt wird:
BlitzMax: [AUSKLAPPEN]
	Method OnUpdate%()
If KeyHit(KEY_CLOSE) Or KeyHit(KEY_ESCAPE) Then Error ""
Button1.X=Button1.X-1
Return 0
End




unterschiedliche Gadgets

Oder ändert mal den "Typ". Sofort ändert sich die Farbe des Gadget:
BlitzMax: [AUSKLAPPEN]
' die "0" ist der Typ:
' Beispiele 0=schwarz, 1=weiß, 2=grau, 3=rosa
Method OnCreate%()
....
Button1= Gadget.Create (5,5, 90,50,1,Top) ' jetzt weißer Button im grauen
Return 0
End





Z-Order: Wer überdeckt wen?

Zwei Gadgets auf der selben Ebene. Das zuerst erstellt wird zu unterst gemalt:
BlitzMax: [AUSKLAPPEN]
	Method OnCreate%()
...
Window = Gadget.Create(0,0,360,480,0,Null) ' Mutter aller Fenster
Top = Gadget.Create (30,30,360,150,2,Window) ' graues Top feld
Button1= Gadget.Create (5,5, 90,50,3,Window) ' rosa Button im grauen
Return 0
End




Verschachtelung

Mutter, Tochter, Enkel:
BlitzMax: [AUSKLAPPEN]
	Method OnCreate%()
SetUpdateRate 10
Window = Gadget.Create(0,0,360,480,0,Null) ' Mutter aller Fenster
Top = Gadget.Create (30,30,360,150,2,Window) ' grauer Top Rahmen
Weiss= Gadget.Create (5,5, 350,140,1,Top) ' weißes Feld im grauen
Button1= Gadget.Create (5,5, 90,50,3,Weiss) ' rosa Button im weißen
Return 0
End




Ein Slider entsteht aus 4 Grundgadgets:
BlitzMax: [AUSKLAPPEN]
Class MyGame Extends App

Global Window:Gadget,Slider:Gadget, Innen:Gadget, Rechts:Gadget, Links:Gadget

Method OnCreate%()
SetUpdateRate 10
Window = Gadget.Create(0,0,360,480,0,Null) ' Mutter aller Fenster
Slider = Gadget.Create (30,30,300,30,2,Window) ' grauer Top Rahmen
Innen = Gadget.Create (66,3,100,24,1,Slider) ' grauer Top Rahmen
Links = Gadget.Create (3,3,30,24,3,Slider) ' grauer Top Rahmen
Rechts = Gadget.Create (270,3,30,24,3,Slider) ' grauer Top Rahmen

Return 0
End
.....
  • Zuletzt bearbeitet von Midimaster am Mi, Jun 19, 2013 11:11, insgesamt 9-mal bearbeitet

Midimaster

Betreff: Kapitel 3: Touch

BeitragSa, Aug 04, 2012 9:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Kapitel 3: Touch

In diesem Kapitel werten wir die Aktionen aus, die in der GUI geschehen können. Hierfür brauchen wir weitere globale Parameter und Konstanten:
BlitzMax: [AUSKLAPPEN]
Class Gadget
...
Const MAUS_DOWN%=1, MAUS_HIT%=2, MAUS_OFF%=0
Global EventSource:Gadget
Global MausX%, MausY%, MausState%, StartMausX%, StartMausY%
...

Im globalen Gadget EventSource merken wir uns das Gadget, das die Maus beim Downklicken getroffen hat.
In den Variablen StartMausX und StartMausY merken wir uns die Koordinate, die die Maus in diesem Moment hatte.

Das Checken der Maus startet in Gadget.Check() und beginnt mit dem Check der Übermutter, die dann rekursiv alle ihre Kinder in der Gadget.CheckOne() rufen wird.

Zunächst sieht die Funktion Gadget.CheckOne() der DrawOne()-Funktionen sehr ähnlich:
BlitzMax: [AUSKLAPPEN]
Method CheckOne:Gadget(offX%,offY%,sX%,sY%,sX2%,sY2%)
Local ChildIn:Gadget, SelfIn:Gadget
If Visible=False Then Return Null
If Enable=False Then Return Null
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return Null
.....



Die Gadget.CheckOne() erhält beim Aufruf wieder die Koordinaten der Mutter sowie den von ihr gesetzten Scissor. Die Tests und Berechnungen sind die gleichen wie bei Draw.

Danach wird untersucht, ob die Maus sich innerhalb des Gadget befindet:
BlitzMax: [AUSKLAPPEN]
....
If MausX>sX And MausX<sX2
If MausY>sY And MausY<sY2
SelfIn=Self
For Local loc:Gadget = EachIn Children.Backwards()
ChildIn=loc.CheckOne (offX, offY, sX, sY, sX2, sY2)
If ChildIn<>Null Then Return ChildIn
Next
EndIf
EndIf
Return SelfIn

Nur wenn dies der Fall ist, werden auch die Kindern durchsucht. Wäre die Maus auch dort, würde dies vorgehen.

Rekursionen sind immer schwer in ihrer Gesamtwirkung zu verstehen. Doch es gilt: "Funktioniert es für ein Element, dann funktioniert es auch für alle anderen, dann funktioniert es auch für das Ganze."

In der Hauptfunktion Gadget.Check() ändert sich mehr: Dort wird der Zustand der Maus geprüft und dann unterschieden, ob sie gedrückt, gehalten oder losgelassen wird:

BlitzMax: [AUSKLAPPEN]
	Function Check:Gadget()
MausAction
If MausState=MAUS_DOWN
If EventSource=Null
EventSource=Mother.CheckOne(0,0,0,0,DeviceWidth(),DeviceHeight())
Else
Print "EVENT_SCROLL !!! Maus Ziehen in Gadget"
EndIf
ElseIf MausState=MAUS_HIT
If EventSource<>Null
Print "EVENT_KLICK !!! Maus Hit in Gadget"
EndIf
EndIf
Return EventSource
End


Ist die Maus gedrückt und war vorher noch kein Gadget als gedrückt gemeldet worden, wird untersucht welches Gadget die Maus anklickt.

Ist die Maus gedrückt und vorher war schon ein Gadget als gedrückt gemeldet worden, handelt es sich wahrscheinlich um ein Scrollen oder ziehen.

War die Maus gedrückt und wurde jetzt losgelassen dann wird ein Event gefeuert: "EVENT_KLICK"

Die Funktion gibt als Rückgabeparameter das Gedgat an, in dem die Action stattgefunden hat. So können wir später im Hauptprogramm darauf zugreifen.




Die Touch-Ereignisse verarbeiten wir in einer eigene Funktion, die in der Lage ist, ziehende Gesten von einfachen Punktberührungen zu unterscheiden:
BlitzMax: [AUSKLAPPEN]
Function MausAction:Void()
MausX=TouchX()
MausY=TouchY()
Local MausDown%=MouseDown()
If MausDown=0
Select MausState
Case MAUS_HIT
MausState=MAUS_OFF
StartMausX=0
StartMausY=0
EventSource=Null
Case MAUS_DOWN
MausState=MAUS_HIT
End Select
Return
Else
Select MausState
Case MAUS_OFF
MausState=MAUS_DOWN
StartMausX=MausX
StartMausY=MausY
End Select
EndIf
End Function


Die Funktion stellt die Werte MausX% MausY% und MausState% zur Verfügung. MausState% kennt dabei drei Zustände:

0=Touch nicht gedrückt
1=Touch ist gedrückt
2=Touch wurde losgelassen

Beim Maus-Klicken wechselt MausState zunächst auf 1 und springt beim Loslassen dann in den Zustand 2. Damit lässt sich "Ziehen" von "Klicken" unterscheiden.


Abschließend wieder der gesamte Code:
BlitzMax: [AUSKLAPPEN]
Strict
Import mojo

Const ON%=1,OFF%=0
Const GADGET_DOWN%=1,GADGET_HIT%=2,GADGET_OFF%=0

Class MyGame Extends App

Global Window:Gadget, Button1:Gadget, Button2:Gadget

Method OnCreate%()
SetUpdateRate 10
Window = Gadget.Create(0,0,360,480,0,Null) ' Mutter aller Fenster
Button1 = Gadget.Create (30,30,100,100,3,Window,"links") ' Button links
Button2 = Gadget.Create (200,30,100,100,3,Window,"rechts") ' Button rechts
Return 0
End

Method OnUpdate%()
If KeyHit(KEY_CLOSE) Or KeyHit(KEY_ESCAPE) Then Error ""
Local Target:Gadget=Gadget.Check()
If Target<> Null
Print "CLICK IN BUTTON " + Target.Text

EndIf
Return 0
End

Method OnRender%()
Cls 0,111,0
Local Zeit%=MilliSecs()
Gadget.Draw
'Print "Zeit=" + (Millisecs()-Zeit)
Return 0
End
End



Function Main%()
New MyGame
Return 0
End



Class Gadget
Const MAUS_DOWN%=1,MAUS_HIT%=2,MAUS_OFF%=0
Global Mother:Gadget, EventSource:Gadget
Global MausX%,MausY%,MausState%,StartMausX%,StartMausY%

Field X%,Y%,B%,H%,Text$,Typ%
Field Parent:Gadget, Visible%, Enable%
Field Children:List<Gadget>= New List <Gadget>


Function Create:Gadget(X%,Y%,B%,H%,Typ%,Eltern:Gadget=Null,Text$="")
Local loc:Gadget=New Gadget()
loc.X=X
loc.Y=Y
loc.B=B
loc.H=H
loc.Typ=Typ
loc.Text=Text
loc.Visible=True
loc.Enable=True
If Eltern=Null
loc.Parent=Null
Mother=loc
Else
loc.Parent=Eltern
Eltern.Children.AddLast loc
EndIf
Return loc
End


Function Draw%()
For Local i%=0 To 0
Mother.DrawOne(0,0,0,0,DeviceWidth(),DeviceHeight())
Next
Return 0
End



Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
If Visible=False Then Return 0

offX=offX+X
offY=offY+Y

If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0

SetScissor sX , sY , (sX2-sX) , (sY2-sY)
' hier das eigentliche Malen:
SetFarbe Typ
DrawRect X,Y,B,H
' und endet wieder
PushMatrix
Translate X,Y
For Local loc:Gadget = EachIn Children
loc.DrawOne offX, offY, sX, sY, sX2, sY2
Next
PopMatrix
Return 0
End



Function Check:Gadget()
MausAction
If MausState=MAUS_DOWN
If EventSource=Null
EventSource=Mother.CheckOne(0,0,0,0,DeviceWidth(),DeviceHeight())
Else
Print "scroll? Maus ziehen in gadget"
Return Null
EndIf
ElseIf MausState=MAUS_HIT
If EventSource<>Null
Print "event !!!"
EndIf
EndIf
Return EventSource
End


Method CheckOne:Gadget(offX%,offY%,sX%,sY%,sX2%,sY2%)
Local ChildIn:Gadget, SelfIn:Gadget
If Visible=False Then Return Null
If Enable=False Then Return Null
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return Null

If MausX>sX And MausX<sX2
If MausY>sY And MausY<sY2
SelfIn=Self
For Local loc:Gadget = EachIn Children.Backwards()
ChildIn=loc.CheckOne (offX, offY, sX, sY, sX2, sY2)
If ChildIn<>Null Then Return ChildIn
Next
EndIf
EndIf
Return SelfIn
End




Function MausAction:Void()
MausX=TouchX()
MausY=TouchY()
Local MausDown%=MouseDown()
If MausDown=0
Select MausState
Case MAUS_HIT
MausState=MAUS_OFF
StartMausX=0
StartMausY=0
EventSource=Null
Case MAUS_DOWN
MausState=MAUS_HIT
End Select
Return
Else
Select MausState
Case MAUS_OFF
MausState=MAUS_DOWN
StartMausX=MausX
StartMausY=MausY
End Select
EndIf
End Function




End






Function SetFarbe:Void(FarbTon%)
Select FarbTon
Case 0
SetColor 1,1,1
Case 1
SetColor 222,222,222
Case 2
SetColor 111,111,111
Case 3
SetColor 200,100,100
End Select
End Function
  • Zuletzt bearbeitet von Midimaster am Do, Jul 04, 2013 0:43, insgesamt 7-mal bearbeitet

Midimaster

Betreff: Kapitel 4: Etwas Styling

BeitragSa, Aug 04, 2012 10:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Kapitel 4: Etwas Styling

In diesem Kapitel wollen wir ordentlich Styling in die GUI bringen:

- Die Gadgets erhalten Rahmen und Innenbereich
- Die Gadgets erhalten Text mit dem AngelFont() Modul
- Die GUI soll auflösungsunabhängig für alle Smartphones werden.


Rahmen und Innenbereich

Grundlage jedes Gadget wird ab jetzt ein sehr kleines PNG-Bild. Es enhält neun Bereiche aus denen die GUI dann die 4 Ecken, 4 Seiten-Rahmen und das Zentrum des Gadget zusammensetzt.

Code: [AUSKLAPPEN]


   ------------------------
   |Ecke     Rand     Ecke|
   |                      |
   |R                    R|
   |a       Mitte        a| 
   |n                    n|
   |d                    d|
   |                      |
   |Ecke     Rand     Ecke|
   ------------------------




Eine eigene Klasse GUIElement wird dafür zuständig sein. GUIElement läd die Vorlagen-PNGs und rendert daraus durch zusammensetzen von 9 Elementen ein Image, dass es dann an die eigentliche GUI zurückgibt. Die stellt ab jetzt das Gadget nicht mehr durch ein DrawRect() dar, sondern jetzt mit DrawImage()

Die Vorlagen-PNGs müssen so beschaffen sein:

Größe mindestens 10x10 Pixel. Daraus entsteht ein Bild ohne Rahmen. Hat die Vorlage 12x12 Pixel so wird das GUI-Element einen Rahmen von 1 Pixel Breite haben (1+10+1=12). Hat die Vorlage 16x16 Pixel so wird das GUI-Element einen Rahmen von 3 Pixel Breite haben (3+10+3=16), u.s.w.

Für die Vorlagen kann man beliebige Namen vergeben. Sie werden von der GUI automatisch gefunden. Jede Vorlage steht für einen neuen Gadget-Typen.

BlitzMax: [AUSKLAPPEN]
Method Render:Image(B#,H#,Text$)
' alles reset:
SetScissor 0,0,DeviceWidth(),DeviceHeight()
SetMatrix 1,0,0,1,0,0
Cls 0,0,0
SetColor 255,255,255

' Rahmenbreite aus Vorlage bestimmen:
Local w#=Img.Width(), h#=Img.Height()
Local Border#=Img.Width()/2-4

' die 4 Ecken:
DrawImageRect Img,0,0,0,0,Border,Border
DrawImageRect Img,B-Border,0,Img.Width()-Border,0,Border,Border
DrawImageRect Img,0,H-Border,0,Img.Height()-Border,Border,Border
DrawImageRect Img,B-Border,H-Border,Img.Width()-Border,Img.Height()-Border,Border,Border

' die 4 Ränder:
PushMatrix
Translate Border,0
Scale (B-2*Border)/(w-2*Border),1
DrawImageRect Img,0,0,Border,0,w-2*Border,Border
PopMatrix
PushMatrix
Translate Border,H-Border
Scale (B-2*Border)/(w-2*Border),1
DrawImageRect Img,0,0,Border,h-Border,w-2*Border,Border
PopMatrix
PushMatrix
Translate 0,Border
Scale 1,(H-2*Border)/(h-2*Border)
DrawImageRect Img,0,0,0,Border,Border,h-2*Border
PopMatrix
PushMatrix
Translate B-Border,Border
Scale 1,(H-2*Border)/(h-2*Border)
DrawImageRect Img,0,0,w-Border,Border,Border,h-2*Border
PopMatrix

' der Innenbereich:
PushMatrix
Translate Border,Border
Scale (B-2*Border)/(w-2*Border),(H-2*Border)/(h-2*Border)
DrawImageRect Img,0,0,Border,Border,w-2*Border,h-2*Border
PopMatrix

' Text hinzufügen:
PushMatrix
Translate B/2,H/2
DrawGadgetText Text,0,0,1
PopMatrix

' Screenshot erstellen:
Local pixels:Int[] =New Int[B*H]
ReadPixels(pixels,0,0,B,H)
Local ScreenShot:Image=CreateImage(B,H)
ScreenShot.WritePixels(pixels, 0, 0, B,H)
Return ScreenShot
End





Text im Gadget

AngelFont ist ein Modul, dass mit Monkey kostenlos ausgeliefert wird. Es befindet sich im Unterverzeichnis "Project/monkey/bananas/beaker". AngelFont kann Zeichensätze korrekt auf Flächen rendern. Zur Einbindung sind nur wenige Schritte nötig:
BlitzMax: [AUSKLAPPEN]
Strict
Import mojo
Import angelfont
....
Class MyGame Extends App
....
Method OnCreate%()
SetUpdateRate 60

GuiElement.Font = New AngelFont()
GuiElement.Font.LoadFont("angel_verdana")

....
End
.....
End

Class GuiElement
...
Global Font:AngelFont, FocusGadget:Gadget

....
Method DrawGadgetText:Void(T$,X%,Y%,Style%)
PushMatrix()
Scale 0.7,0.7
Translate X,Y-Font.TextHeight("T")/2
SetColor 1,1,1
Font.DrawText T, X, Y,Style
PopMatrix()
End
End


Nun muss noch ein Ordner MyGame.data angelegt werden, in den folgende drei Dateien aus dem "Project/monkey/bananas/beaker" kopiert werden müssen:
Code: [AUSKLAPPEN]
angel_verdana.fnt
angel_verdana.png
angel_verdana.txt


Außerdem müssen die drei Dateien angelfont.monkey, kernpair.monkey, und char.monkey in den selben Ordner kopiert werden, wo sich unser Hauptcode MyGame.monkey befindet



Auflösungsunabhängige Darstellung



Das auflösungsunabhängige Darstellen ist weitaus leichter, als man glauben könnte. Nur wenige Zeilen ändern alles:


Wir führen zwei Variable XRatio# und YRation# ein, die zukünftig alle Zeichen aktionen dehnen. So können wir immer für die gleiche "virtuelle" Bildschirmgröße 320x480 programmieren und die Dehungsfaktoren werden dies korrekt auf das jeweilige Gerät rendern.
BlitzMax: [AUSKLAPPEN]
Class MyGame Extends App

Method OnCreate%()
SetUpdateRate 60
Gadget.XRatio=DeviceWidth()/360.0
Gadget.YRatio=DeviceHeight()/480.0
....
End
.....
End
....
Class Gadget
Global Liste: List <Gadget>= New List <Gadget>
Global Font:AngelFont
Global MausX%,MausY%,MausHit%,StartMausX%,StartMausY%,XRatio#,YRatio#
.....

Function Draw%()
Scale XRatio,YRatio
....
End
....

Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
.....
SetScissor sX*XRatio , sY*YRatio , (sX2-sX)*XRatio , (sY2-sY)*YRatio
....
End
End




Bei den Touch()-Aktionen werden Sie die Werte stauchen und so genau das Gegnenteil bewirken.
BlitzMax: [AUSKLAPPEN]
Class Gadget
....
Function MausAction:Void()
MausX=TouchX()/XRatio
MausY=TouchY()/YRatio
....
End


Beim Zeichnen gibt es dank strenger Trennung des Codes nur zwei Stellen, wo die die Dehnung erwähnen müssen:
BlitzMax: [AUSKLAPPEN]
Class Gadget
.....

Function Draw%()
Scale XRatio,YRatio
....
End
....

Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
.....
SetScissor sX*XRatio , sY*YRatio , (sX2-sX)*XRatio , (sY2-sY)*YRatio
....
End

Die Monkey-Funktion Scale() ändert nicht nur Breite und Höhe aller Zeichenelementen. Sie beeinflusst auch die X und Y-Koordinaten.

Einzig der Scissor muss noch umgerechnet werden. Das war's.


Nachtrag zum Styling:

schon im vorherigen Kapitel habe ich aus die eine DrawRect()-Zeile, die uns bisher gereicht hatte um ein Gadget vorläufig zu malen, durch ein schöneres Design mit Rahmen und Innenrechteck in zwei verschiedenn Farben ersetzt.

Die Farben sind in der Funktion SetFarbe() notiert. sie beginnen mit der Nummer 100 für GadgetTyp 0, 110 für GadgetTyp 1, 120 für GadgetTyp 2, usw. Dadurch kann ich jetzt bis zu 10 Farben pro Gadget definieren: 100, 101, 102..bis 109 und so bis zu 10 grafische Elemente kombinieren um ein Gasget wirkungsvoller darzustellen.

Abschließend noch der Code, wie er sich bs jetzt gesamt darstellt:
BlitzMax: [AUSKLAPPEN]
Strict
Import mojo
Import angelfont
Global Game:MyGame, Debug$, MausIn%

Class MyGame Extends App
Method OnCreate%()
SetUpdateRate 60
Gadget.XRatio=DeviceWidth()/360.0
Gadget.YRatio=DeviceHeight()/480.0
' id, x, y, b, h, Typ, Parent-ID
Gadget.Font = New AngelFont()
Gadget.Font.LoadFont("angel_verdana")

Gadget.Create 1,0,0,360,480,3,0,"" ' Mutter aller Fenster
Gadget.Create 2,0,0,360,120,3,1,"" ' Mutter für Top feld
Gadget.Create 5,2,2, 356,56,1,1,""
Gadget.Create 6,5,65, 90,50,0,2,"A"
Gadget.Create 7,105,65, 90,50,0,2,"B"
Gadget.Create 8,205,65, 70,50,0,2,"C"
Gadget.Create 9,285,65, 70,50,0,2,"D"
Return 0
End

Method OnUpdate%()
MausIn=Gadget.Check()
If Gadget.MausHit=2
Debug="click " + MausIn
EndIf
Return 0
End

Method OnRender%()
Cls 0,111,0
Gadget.Draw
SetColor 225,225,225
SetScissor 0,0,999,999
DrawText "Maus=" + MausIn + " Hit=" + Gadget.MausHit + "Debug=" + Debug,10,10
Return 0
End
End

Function Main%()
Game=New MyGame()
Return 0
End

Class Gadget
Global Liste: List <Gadget>= New List <Gadget>
Global Font:AngelFont
Global MausX%,MausY%,MausHit%,StartMausX%,StartMausY%,WarScrolling%,,XRatio#,YRatio#
Field Id%,X%,Y%,B%,H%,Typ%,Text$
Field Parent:Gadget, Visible%, Enable%
Field Children:List<Gadget>= New List <Gadget>



Function MausAction:Void()
MausX=TouchX()/XRatio
MausY=TouchY()/YRatio
If MausHit<>MouseDown()
Select MausHit
Case 0
MausHit=1
StartMausX=MausX
StartMausY=MausY
WarScrolling=MausX+MausY
Case 1
MausHit=2
StartMausX=0
StartMausY=0
If Abs(WarScrolling-(MausX+MausY))>20
MausHit=0
EndIf
Case 2
MausHit=0
WarScrolling=0
End Select
EndIf
End Function



Function Create%(Id%,X%,Y%,B%,H%,Typ%,ElternID%,Text$="")
Local loc:Gadget=New Gadget()
loc.Id=Id
loc.X=X
loc.Y=Y
loc.B=B
loc.H=H
loc.Typ=Typ
loc.Text=Text
loc.Visible=True
loc.Enable=True
If ElternID>0
loc.Parent=Gadget(ElternID)
loc.Parent.Children.AddLast loc
Else
loc.Parent=Null
EndIf
Liste.AddLast loc
Return 0
End


Function Gadget:Gadget(Id%)
For Local loc:Gadget = EachIn Liste
If Id=loc.Id Then Return loc
Next
Return Null
End


Function Draw%()
Scale XRatio,YRatio
Liste.First.DrawOne (0,0,0,0,999,999)
Return 0
End Function


Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
If Visible=False Then Return 0
SetFarbe Typ
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0
SetScissor sX*XRatio , sY*YRatio , (sX2-sX)*XRatio , (sY2-sY)*YRatio
' hier das eigentliche Malen:
SetFarbe 100+Typ*10
DrawRect offX, offY,B,H
SetFarbe 101+Typ*10 + Sgn(Check()=Id)
DrawRect offX+2, offY+2,B-4,H-4
SetFarbe 103+Typ*10
DrawGadgetText Text, offX+B/2, offY+H/4,1

'
For Local loc:Gadget = EachIn Children
loc.DrawOne (offX+2, offY+2, sX+2, sY+2 , sX2-2, sY2-2)
Next
Return 0
End

Method DrawGadgetText:Void(T$,X%,Y%,Style%)
Font.DrawText T, X, Y,Style
End

Function Check%()
MausAction
Return Liste.First.CheckOne (0,0,0,0,999,999)
End

Method CheckOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
Local In%,LastIn%=0
If Visible=False Then Return 0
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0
If MausX>sX And MausX<sX2
If MausY>sY And MausY<sY2
LastIn=Id
For Local loc:Gadget = EachIn Chidren.Backwards()
In=loc.CheckOne (offX+2, offY+2, sX+2, sY+2 , sX2-2, sY2-2)
If Enable=True
If In<>0 Then Return In
EndIf
Next
If Enable=False Then Return -1
Scroll
EndIf
EndIf
Return LastIn
End

Method Scroll:Void()
End
End


Function SetFarbe:Void(FarbTon%)
Select FarbTon
Case 0
SetColor 0,0,0
Case 1
SetColor 255,255,255
Case 100
SetColor 222,222,222
Case 101
SetColor 90,90,90
Case 102
SetColor 90,90,110
Case 103
SetColor 222,222,222
Case 110
SetColor 150,150,150
Case 111
SetColor 244,244,244
Case 112
SetColor 244,244,244
Case 113
SetColor 55,55,55
Case 120
SetColor 150,150,150
Case 121
SetColor 50,50,50
Case 122
SetColor 50,50,70
Case 123
SetColor 255,255,255
Case 130,131,132,133
SetColor 1,1,1
End Select
End Function



in der nächste Lektion geht es um das Scrollen....
  • Zuletzt bearbeitet von Midimaster am Do, Jul 04, 2013 1:26, insgesamt 5-mal bearbeitet

Midimaster

Betreff: Kapitel 5: Scrolling

BeitragSo, Aug 05, 2012 9:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Kapitel 5: Scrolling

Heute geht es um das Bewegen eines Gadget in seiner Mutter. Dabei gibt es mehrere Parameter. Zunächst könnte das Bewegen verboten sein oder man kann horizontal oder vertikal scrollen oder beide Richtungen sind erlaubt. Außerdem sehe ich zwei grundsätzliche Arten der Bewegung Grenzen zu setzen: Das innere Objekt, darf so weit im äußeren Objekt bewegt werden, bis es an eine äußere Grenze stößt: IN_BORDER. (Beispiel:Billiardkugel auf dem Billiardtisch). Oder das Objekt ist größer als seine Mutter und darf nur solange bewegt werden, bis ein Rand sichtbar werden würde: OUT_BORDER. (Beispiel: großes Image im Fenster).

Daher führen wir diese globalen Konstanten und einige Variable ein:
BlitzBasic: [AUSKLAPPEN]
Const MAUS_DOWN%=1,MAUS_HIT%=2,MAUS_OFF%=0
Const HORIZONTAL%=1,VERTICAL%=2,BOTH%=3,IN_BORDER%=4,OUT_BORDER%=8,BORDER%=12
....
Class Gadget
Global Liste: List <Gadget>= New List <Gadget>
Global Font:AngelFont
...
Global WarScrolling%
...
Field Parent:Gadget, Visible%, AllowScroll%, Enable%




Nun könnte es immer sein, dass zwar ein Gadget nicht scrollen darf, aber seiner Mutter ist es erlaubt. z.B. eine Liste von Texten ist länger als das Fenster. Dann gibt es drei Gadgets-Ebenen: Das Fenster, der Listen-Container und viele Label-Gadgets, die sich dicht an dicht auf dem Container befinden. Nun soll sich mit einer Schiebe-Geste auf ein Label-Gadget nicht das Gadget gegen seine Brüder verschieben lassen, aber der darunterliegende Container im Fenster schon. Also müssen die Touch()-Aktionen auch an die darunterliegenden Mütter weitergereicht werden.

BlitzMax: [AUSKLAPPEN]
	Method Scroll:Void()
If MausHit=MAUS_DOWN
If AllowScroll =OFF
If Parent<>Null
Parent.Scroll
EndIf
Else
...

Dies bewirkt, dass die Scroll-Geste dann weitergereicht wird, wenn das Gadget selbst nicht scrollen darf.



Darf das Gedget selbst scrollen, dann folgen zwei Routinen für vertikale und horizontale Bewegung. Hier die vertikale:

BlitzMax: [AUSKLAPPEN]
...				Else				
If AllowScroll & VERTICAL
If StartMausY=MausY Then Return
Y =Y+MausY-StartMausY
StartMausY=MausY
If AllowScroll & BORDER
If AllowScroll & OUT_BORDER
If Y>0 Then Y=0
If Y+H<Parent.H Then Y=Parent.H-H
Else
If Y<0 Then Y=0
If Y+H>Parent.H Then Y=Parent.H-H
EndIf
EndIf
EndIf


Bei der Erstberührung wurde die Position des Maus in StartMausY% vermerkt. Hat seitdem eine weitere Maus-Bewegung stattgefunden wird sie jetzt zur Gadget-Position addiert und StartMaus relativiert. Abschließend wird noch geprüft, ob die vorgegebenen Grenzen eingehalten werden. Bei OUT_BORDER darf der Rand des Gadgets nicht innerhalb seiner Mutter sichtbar werden. Bei IN_BORDER darf er das Gadget nicht verlassen.


Die gleiche Routine wird anschließend mit horizontaler Bewegung durchgegangen.


Das Erstellen eines scrollbaren Gadgets mit einigen Kindern macht man so:
BlitzMax: [AUSKLAPPEN]
			Gadget.Create 3,0,120,360,260,0,1,"" 'Mutter  für Scrollbereich
Gadget.Create 4,0,0,360,760,0,3,"" ' Scrollbereich

Gadget.Gadget(4).AllowScroll=VERTICAL|OUT_BORDER
For Local i%=0 To 10
Gadget.Create 20+i,0,60*i,360,62,2,4,"Entry "+ (20+i)
Next

Zunächst wird ein feststehendes Fenster erstellt (Mutter). Darin ein Listen-Container mit sehr großem H=760
Anschließend wird die Scroll-Eigenschaft festgelegt. Nun folgen 10 Kinder mit Text-Einträgen.



Und hier wieder der fertige Code:
BlitzMax: [AUSKLAPPEN]
Strict
Import mojo
Import angelfont
Global Game:MyGame, Debug$, MausIn%

Const ON%=1,OFF%=0
Const MAUS_DOWN%=1,MAUS_HIT%=2,MAUS_OFF%=0
Const HORIZONTAL%=1,VERTICAL%=2,BOTH%=3,IN_BORDER%=4,OUT_BORDER%=8,BORDER%=12

Class MyGame Extends App
Method OnCreate%()
SetUpdateRate 60
Gadget.XRatio=DeviceWidth()/360.0
Gadget.YRatio=DeviceHeight()/480.0
' id, x, y, b, h, Typ, Parent-ID
Gadget.Font = New AngelFont()
Gadget.Font.LoadFont("angel_verdana")

Gadget.Create 1,0,0,460,380,3,0,"" ' Mutter aller Fenster
Gadget.Create 2,0,0,360,120,3,1,"" ' Mutter für Top feld
Gadget.Create 5,2,2, 356,56,1,1,""
Gadget.Create 6,5,65, 90,50,0,2,"A"
Gadget.Create 7,105,65, 90,50,0,2,"B"
Gadget.Create 8,205,65, 70,50,0,2,"C"
Gadget.Create 9,305,65, 70,50,0,2,"D"
Gadget.Create 3,0,120,360,260,0,1,"" 'Mutter für Scrollbereich
Gadget.Create 4,0,0,360,760,0,3,"" ' Scrollbereich

Gadget.Gadget(4).AllowScroll=VERTICAL|OUT_BORDER
For Local i%=0 To 10
Gadget.Create 20+i,0,60*i,360,62,2,4,"Entry "+ (20+i)
Next
Return 0
End

Method OnUpdate%()
MausIn=Gadget.Check()
If Gadget.MausHit=2
Gadget.Gadget(5).Text="click " + MausIn
EndIf
If Gadget.MausHit=2
Debug="click " + MausIn
EndIf
Return 0
End

Method OnRender%()
Cls 0,111,0
Gadget.Draw
SetColor 225,225,225
SetScissor 0,0,999,999
DrawText "Maus=" + MausIn + " Hit=" + Gadget.MausHit + "Debug=" + Debug,10,10
Return 0
End
End

Function Main%()
Game=New MyGame()
Return 0
End

Class Gadget
Global Liste: List <Gadget>= New List <Gadget>
Global Font:AngelFont
Global WarScrolling%
Global MausX%,MausY%,MausHit%,StartMausX%,StartMausY%,XRatio#,YRatio#,MustRender%
Field Id%,X%,Y%,B%,H%,Typ%,Text$
Field Parent:Gadget, Visible%, Enable%, AllowScroll%
Field Children:List<Gadget>= New List <Gadget>




Function MausAction:Void()
MausX=TouchX()/XRatio
MausY=TouchY()/YRatio
If MausHit<>MouseDown()
Select MausHit
Case 0
MausHit=1
StartMausX=MausX
StartMausY=MausY
WarScrolling=MausX+MausY
Case 1
MausHit=2
StartMausX=0
StartMausY=0
If Abs(WarScrolling-(MausX+MausY))>20
MausHit=0
EndIf
Case 2
MausHit=0
WarScrolling=0
End Select
EndIf
End Function



Function Create%(Id%,X%,Y%,B%,H%,Typ%,ElternID%,Text$="")
Local loc:Gadget=New Gadget()
loc.Id=Id
loc.X=X
loc.Y=Y
loc.B=B
loc.H=H
loc.Typ=Typ
loc.Text=Text
loc.Visible=True
loc.Enable=True
If ElternID>0
loc.Parent=Gadget(ElternID)
loc.Parent.Children.AddLast loc
Else
loc.Parent=Null
EndIf
Liste.AddLast loc
Return 0
End


Function Gadget:Gadget(Id%)
For Local loc:Gadget = EachIn Liste
If Id=loc.Id Then Return loc
Next
Return Null
End


Function Draw%()
Scale XRatio,YRatio
Liste.First.DrawOne (0,0,0,0,999,999)
Return 0
End Function


Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
If Visible=False Then Return 0
SetFarbe Typ
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0
SetScissor sX*XRatio , sY*YRatio , (sX2-sX)*XRatio , (sY2-sY)*YRatio
' hier das eigentliche Malen:
SetFarbe 100+Typ*10
DrawRect offX, offY,B,H
SetFarbe 101+Typ*10 + Sgn(Check()=Id)
DrawRect offX+2, offY+2,B-4,H-4
SetFarbe 103+Typ*10
DrawGadgetText Text, offX+B/2, offY+H/4,1

'
For Local loc:Gadget = EachIn Children
loc.DrawOne (offX+2, offY+2, sX+2, sY+2, sX2-2, sY2-2)
Next
Return 0
End

Method DrawGadgetText:Void(T$,X%,Y%,Style%)
Font.DrawText T, X, Y,Style
End

Function Check%()
MausAction
Return Liste.First.CheckOne (0,0,0,0,999,999)
End

Method CheckOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
Local In%,LastIn%=0
If Visible=False Then Return 0
offX=offX+X
offY=offY+Y
If offX>sX Then sX=offX
If offY>sY Then sY=offY
If offX+B<sX2 Then sX2=offX+B
If offY+H<sY2 Then sY2=offY+H
If (sX2<sX) Or (sY2<sY) Then Return 0
If MausX>sX And MausX<sX2
If MausY>sY And MausY<sY2
LastIn=Id
For Local loc:Gadget = EachIn Children.Backwards()
In=loc.CheckOne (offX+2, offY+2, sX+2, sY+2 , sX2-2, sY2-2)
If Enable=True
If In<>0 Then Return In
EndIf
Next
If Enable=False Then Return -1
Scroll
EndIf
EndIf
Return LastIn
End

Method Scroll:Void()
If MausHit=MAUS_DOWN
If AllowScroll =OFF
If Parent<>Null
Parent.Scroll
EndIf
Else
If AllowScroll & VERTICAL
If StartMausY=MausY Then Return
Y =Y+MausY-StartMausY
StartMausY=MausY
If AllowScroll & BORDER
If AllowScroll & OUT_BORDER
If Y>0 Then Y=0
If Y+H<Parent.H Then Y=Parent.H-H
Else
If Y<0 Then Y=0
If Y+H>Parent.H Then Y=Parent.H-H
EndIf
EndIf
EndIf
If AllowScroll & HORIZONTAL
If StartMausX=MausX Then Return
X =X+MausX-StartMausX
StartMausX=MausX
If AllowScroll & BORDER
If AllowScroll & OUT_BORDER
If X>0 Then X=0
If X+B<Parent.B Then X=Parent.B-B
Else
If X<0 Then X=0
If X+B>Parent.B Then X=Parent.B-B
EndIf
EndIf
EndIf
EndIf
EndIf
End
End


Function SetFarbe:Void(FarbTon%)
Select FarbTon
Case 0
SetColor 0,0,0
Case 1
SetColor 255,255,255
Case 100
SetColor 222,222,222
Case 101
SetColor 90,90,90
Case 102
SetColor 90,90,110
Case 103
SetColor 222,222,222
Case 110
SetColor 150,150,150
Case 111
SetColor 244,244,244
Case 112
SetColor 244,244,244
Case 113
SetColor 55,55,55
Case 120
SetColor 150,150,150
Case 121
SetColor 50,50,50
Case 122
SetColor 50,50,70
Case 123
SetColor 255,255,255
Case 130,131,132,133
SetColor 1,1,1
End Select
End Function


Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
  • Zuletzt bearbeitet von Midimaster am Do, Aug 09, 2012 20:35, insgesamt einmal bearbeitet

Midimaster

Betreff: Keyboard auf dem Android

BeitragDi, Aug 07, 2012 0:31
Antworten mit Zitat
Benutzer-Profile anzeigen
Kapitel 6: Keyboard auf dem Android

nun werden wir ein Input-Gadget hinzufügen und das Programm ein erstes Mal auf einem Android-Handy testen.

Dazu sind einige Vorbereitungen nötig.

Um für das schnelle Testen zukünftig das Target Html5 verwenden zu können, wollen wir die Ausmaße des Browsers an unser Handy anpassen. Dazu ändern wir die von Monkey allgemein vorgegebene Canvas-Größe von 640x480 auf 320x480.

Beim ersten Kompilieren hat Monkey einen Ordner MyGame.build angelegt, wo es beim Kompilieren die verschiedenen Target-Apps speichert. So gibt es nun in dem Ordner MyGame.build\html5\ eine Datei MonkeyGame.html. Wir öffnen sie mit Editpad und ändern folgende Zeile:

Code: [AUSKLAPPEN]
<canvas id="GameCanvas" onclick="this.focus();" oncontextmenu="return false;" width=320 height=480 tabindex=1></canvas>


Durch Einsetzen der entsprechenden Werte liese sich hier jede Handy-Display-Größe simulieren. Unsere GUI passt sich übrigens bereits immer an und wird die eigene Grafikausgabe stets formatfüllend an das Display anpassen.

Die App für das Target Android legt Monkey in den Ordner MyGame.build\android\. Auch dort läßt sich bereits jetzt eine wichtige Änderung treffen:


Orientation: User
Im Ordner MyGame.build\html5\ öffnen wir die Datei CONFIG.TXT und ändern folgende Zeile:
Code: [AUSKLAPPEN]
android:screenOrientation="user"
. Dies ermöglicht uns später das breitere QWERTZ Keyboard zu verwenden.


Um aus einen 0815-Gadget eine Text-Eingabebox zu machen sind folgende Schritte notwendig:

Zunächst legen wir zum ersten Mal eine Kennung für TEXT_FIELD fest:
BlitzMax: [AUSKLAPPEN]
Strict
Import mojo
Import angelfont
...
Const TEXT_FIELD%=1


Diese Kennung verwenden wir des besseren Übersicht nun auch immer ,wenn wir ein Textfield erstellen. also ändert sich die Create-Zeile des Gadget Nr 5:
BlitzMax: [AUSKLAPPEN]
Class MyGame Extends App
Method OnCreate%()
......
Gadget.Create 5,2,2, 356,56,TEXT_FIELD,1,""



Und beim Malen unterscheiden wir auch:
BlitzMax: [AUSKLAPPEN]
Class Gadget
.....
Method DrawOne%(offX%,offY%,sX%,sY%,sX2%,sY2%)
If Visible=False Then Return 0
.....
SetScissor sX*XRatio , sY*YRatio , (sX2-sX)*XRatio , (sY2-sY)*YRatio
' hier das eigentliche Malen:
SetFarbe 100+Typ*10
DrawRect offX, offY,B,H
SetFarbe 101+Typ*10 + Sgn(Check()=Id)
DrawRect offX+2, offY+2,B-4,H-4
SetFarbe 103+Typ*10
If Typ=TEXT_FIELD
Local T$=Text
If Blinkt=ON And Focus=Id Then
T=T+"|"
Else
T=T+" "
EndIf
DrawGadgetText T, offX+10, offY+H/4,0
Else
DrawGadgetText Text, offX+B/2, offY+H/4,1
EndIf


Das Textfield wird nun einen blinkenden Cursor haben, sobald es den Focus erhält. Dazu bekommt die Klasse zwei neue Variable und ein wenig code in der Check()-Funktion:

BlitzMax: [AUSKLAPPEN]

Class Gadget
....
Global Blinkt%, BlinkTimer%, Focus%, KeyboardShown%

....
Function Check%()
MausAction
If BlinkTimer<MilliSecs()
BlinkTimer=MilliSecs()+500
Blinkt=1-Blinkt
EndIf

If MausHit>0
Focus=Liste.First.CheckOne (0,0,0,0,999,999)
Return Focus
EndIf
Return 0
....



Nun müssen wir nur noch die virtuelle Tastatur rufen, wenn das Textfield den Focus erhält und wir verstecken sie wieder, wenn dort die RETURN-Taste gedrückt wird.
BlitzMax: [AUSKLAPPEN]
	Function Check%()
....
If MausHit>0
Focus=Liste.First.CheckOne (0,0,0,0,999,999)
If MausHit=MAUS_HIT And KeyboardShown=OFF And Gadget(Focus).Typ= TEXT_FIELD Then
KeyboardShown=ON
Gadget(5).Text="Keyboard ON "
EnableKeyboard()
Else
KeyboardShown=OFF
Gadget(5).Text="Keyboard OFF "
DisableKeyboard()
EndIf
Return Focus
EndIf
Return 0



spät... müde... fortsetzung folgt....
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe

Neue Antwort erstellen


Übersicht Andere Programmiersprachen FAQs und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group