GUI Tutorial für Anfänger

Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials

Neue Antwort erstellen

 

Seven

Betreff: GUI Tutorial für Anfänger

BeitragSo, Mai 20, 2012 2:14
Antworten mit Zitat
Benutzer-Profile anzeigen
GUI Tutorial für Anfänger

Vorwort:
Hallo, da ich schon seit längerem an einigen GUI Elementen arbeite, kommt nun ein Tutorial, dass zum einen
für die ist, die ihre eigenen GUI Elemente machen wollen. Zum anderen will ich sehen, ob mein gesammeltes
Wissen für ein Tutorial ausreicht.

-----------------------------------------------------------------------------------------------------------------------------------

Button:

BlitzMax: [AUSKLAPPEN]

Rem
Ich beginne mit dem Button. Der sollte kein Problem darstellen,
ich werde aber trotzdem auf ihn eingehen, da ich bei allen GUI Elementen eine
ähnliche Struktur verwende. Ich zeige dabei nur meine Art an. Du kannst das gerne
anders machen, dich inspirieren lassen, oder sonstiges. Meine Version hat bisher
funktioniert, deswegen sollte sie auch für mehrere Leute tauglich sein.

Naja, los gehts :)
EndRem


Rem
Als erstes kommt Superstrict, sodass man sich sicher sein kann, dass man alle
Variablen am Anfang findet.
End Rem

SuperStrict
'-------------------------------
'Unsere Variablen
'-------------------------------
Global GW:Short, GH:Short 'Höhe und Breite der Auflösung
Global MX:Short, MY:Short, MH1:Byte 'Variablen für MouseX() usw.
'-------------------------------
'Types
'-------------------------------
Rem
Ja, hier benutze ich keinen Type. Wieso nicht? Weil es auch ohne geht. Sicher,
man kann welche einsetzen, aber ein Button (zumindest meiner) ist so aufgebaut,
dass keine Globalen Variablen nötig sind. Wenn das der Fall ist, dann kann
man mehrere davon benutzen und von einander unterscheiden, obwohl man überhaupt
keine Types dafür hat, aber das wirst du gleich noch sehen können.
End Rem

'-------------------------------
GW = 800
GH = 600
Graphics GW, GH, 0, 60 '800 x 600 @ 60 hz
Rem
Ein grauer Hintergrund. Ich färbe den Hintergrund gerne so, dass er eine deutlich
andere Farbe hat, als alles, was sich in den folgenden Funktionen befindet.

So kann man sehen, ob z.B. die Schrift übersteht, oder sowas.
End Rem

SetClsColor 60, 60, 60
'-------------------------------
'HauptSchleife
'-------------------------------
Repeat
Rem
Cls & MX, MY & MH1. Ich speichere MouseX() und co. am Anfang immer in Variablen.
Zum einen, weil es so bequemer ist und zum anderen, weil es einen Fehler gibt,
der dadurch vermieden wird, aber dazu später mehr bei der Checkbox.
End Rem

Cls
MX = MouseX()
MY = MouseY()
MH1= MouseHit(1)
Rem
Hier gleich zwei Buttons, um zu beweißen, dass man hier nicht unbedingt Types
braucht.
End Rem

If Button("Button 1", 50, 100) Then Print "Button 1 wurde gedrückt :'("
If Button("Button 2", 50, 150) Then Print "Button 2 wurde gedrückt Wink"

Flip
Until AppTerminate() Or KeyDown(KEY_Escape)
End
'-------------------------------
'Unsere Funktionen'
Function Button:Byte(txt:String, X:Short, Y:Short)
Local Width :Short, Height :Byte 'Höhe & Breite des Buttons
Local txtWidth:Short, txtHeight:Byte 'Höhe & Breite von dem Text, der in den Button soll (hier z.B. Button 1)
Local txtSpaceW:Byte, txtSpaceH:Byte 'Freiraum zwischen Button und Text, damit der Text nicht gequetscht aussieht
Local Feedback :Byte 'Rückgabewert, der uns sagt, ob der Button betätigt wurde.

'Deklarierungen
txtWidth = TextWidth (txt)
txtHeight = TextHeight(txt)

txtSpaceW = 20
txtSpaceH = 6

Width = txtWidth + txtSpaceW
Height = txtHeight + txtSpaceH

Rem
Der Button selbst wird gezeichnet. Hier in einem Rot. Man könnte / sollte die Möglichkeit offen
halten, den Button anhand eines Bildes zu zeichnen.
End Rem

SetColor 178, 34 , 34
DrawRect X, Y, Width, Height

Rem
Im Folgenden wird bestimmt, ob der Button Gedrückt wurde. Man könnte statt meiner Kollisionserkennung
sicher auch etwas anderes nutzen. (z.B. Rectsoverlap)
Die anderen GUI Elemente verwenden fast alle das selbe Prinzip.
End Rem

If MH1 Then '/MouseDown(1)
If MX > X And MX < ( X + Width ) Then
If MY > Y And MY < ( Y + Height ) Then
Rem
Es ist immer schön etwas zu sehen, wenn man den Button betätigt hat, deswegen wird
hier noch ein dunkel rotes Rechteck innerhalb des Buttons gemalt.
End Rem

SetColor 139, 0, 0
DrawRect X + Width * 0.05, Y + Height * 0.05 , Width * 0.9, Height * 0.9
Feedback = 1 'Der Button wurde angeklickt und ich speichere das in Feedback.

EndIf
EndIf
EndIf

SetColor 255 ,255 , 255
DrawText txt, X + txtSpaceW / 2, Y + txtSpaceH / 2 'Der Button Text
Rem
Feedback wird zurückgegeben. Wenn Feedback 1 ist, dann wird die If Bedingung, in dem sich der
Button befindet, erfüllt. Fertig ist der Button :)
End Rem

Return Feedback
End Function

-----------------------------------------------------------------------------------------------------------------------------------

CheckBox

BlitzMax: [AUSKLAPPEN]

Rem
Und weiter geht es mit der CheckBox. Denk daran, dass die Elemente auf einander
aufbauen, von daher wird es öfters heißen "siehe Button", da ich dort exat das
selbe gemacht habe.
End Rem

SuperStrict
'-------------------------------
'Unsere Variablen
'-------------------------------
Global GW:Short, GH:Short 'siehe Button :D
Rem
siehe Button 2 :D bzw. hier kläre ich auf, zu welchem Fehler das nicht verwenden
von "MouseX() und co." - Variablen führen kann.
End Rem

Global MX:Short, MY:Short, MH1:Byte
Rem
Für CheckBoxen brauchen wir sehr wohl globale Variablen und da wir mehrere
von einander unterscheiden wollen, brauchen wir Types und für Types brauchen
wir Listen und die erstelle ich hier.

Zusätzlich braucht man in meiner Variante einen Zähler für die Checkboxen,
aber dazu später mehr.
End Rem

Global CheckBoxList :TList = New TList 'Liste für die Checkboxen
Global CheckBoxCount:Byte 'Anzahl der Checkboxen
'-------------------------------
'Types
'-------------------------------
Rem
Ein Type für die CheckBox. Innerhalb des Types speichere ich durch active,
ob die Checkbox "aktiv" ist und mit ID eine Zahl, durch die man die Checkboxen von
einander unterscheiden kann.

Außerdem nutze ich hier die Methode New, um die Checkboxen automatisch zählen zu
lassen.
End Rem

Type TCheckBox
Field active:Byte
Field ID:String
Method New:TCheckBox()
CheckBoxCount = CheckBoxCount + 1
End Method
End Type
Global Box:TCheckBox 'Type globalisieren
'-------------------------------
GW = 800 'Siehe Button ...
GH = 600
Graphics GW, GH, 0, 60
SetClsColor 60, 60, 60
'-------------------------------
'HauptSchleife
'-------------------------------
Repeat
Cls
MX = MouseX()
MY = MouseY()
MH1= MouseHit(1)
Rem
Hier gleich fünf Checkboxen zum testen :)
End Rem

If CheckBox( 50, 100 ) Then Print "CheckBox 1"
If CheckBox( 50, 150 ) Then Print "CheckBox 2"
If CheckBox( 50, 200 ) Then Print "CheckBox 3"
If CheckBox( 50, 250 ) Then Print "CheckBox 4"
If CheckBox( 50, 300 ) Then Print "CheckBox 5"

Flip
Until AppTerminate() Or KeyDown(KEY_Escape)
End
'-------------------------------
'Unsere Funktionen'
Function CheckBox:Byte(X:Short, Y:Short)
Local Dimension:Byte = 30, ID:String 'Die Größe der Box und die ID
Local Varification:Byte, Feedback:Byte 'Ein Zähler für die Unterscheidung der Boxen und der Rückgabewert
Rem
Damit man eine Box wiedererkennen kann, muss man ihr etwas geben, womit sie einzigartig ist.
Das ist sozusagen ihr Name. In diesem Fall muss der Name aus den Koordinaten erschaffen werden,
da sie zusammengesetzt keine zwei mal vorkommen müssten.
End Rem

ID = String(X) + String(Y)

Rem
Und jetzt geht es los. Die folgende Abfrage ist wichtig, da ich sie in anderen Elementen auch so verwenden
werde. Ziel der Abfrage ist es, herauszufinden, welche CheckBox momentan vorliegt und den entsprechenden
Type dazu aufzurufen um damit weiter zu machen.
End Rem

If Box:TCheckBox = Null Then 'Zuerst die Frage, ob überhaupt schon ein Type für eine CheckBox existiert.
Box:TCheckBox = New TCheckBox 'Wenn nicht, dann wird einer erstellt (/geboren ^^),
ListAddLast( CheckBoxList, Box ) 'in die Liste gepackt
Box.ID = ID 'und er bekommt gleich einen Namen.
Else
Rem
Sollte schon mindestens ein Type für eine Checkbox existieren, so muss festgestellt werden, ob der Type
denn auch der richtige für die Checkbox ist. Das erreiche ich mit Hilfe des Namens. Der Type hat einen
Namen und die Checkbox auch und falls beide den selben Namen haben, so hat man den richtigen Type vor
sich und die Schleife kann beendet werden.
End Rem

For Box:TCheckBox = EachIn CheckBoxList
If Box.ID = ID Then Exit
Rem
Falls nun keiner der Types zur Checkbox passt, wird gezählt. Dafür habe ich am Anfang CheckboxCount
eingeführt und dafür habe ich Varification. Varification wird immer weiter hoch gezählt, sofern
der richtige Type nicht gefunden wird.
End Rem

Varification = Varification + 1
Next
Rem
Wenn es den richtigen Type nicht gibt, dann ist die Schleife alle Types durchgegangen. Die Anzahl der
Types habe ich in CheckBoxCount gespeichert und Varification erreicht in dem Fall diese Anzahl.
In diesem Fall wird der richtige Type erschaffen und mit den Werten gefüttert.
End Rem

If Varification = CheckBoxCount Then
Box:TCheckBox = New TCheckBox
ListAddLast( CheckBoxList, Box )
Box.ID = ID
EndIf
EndIf

SetColor 255, 255, 255
'Zeichnen der Box
DrawRect X , Y , Dimension / 10, Dimension 'Rechte Seite
DrawRect X + Dimension - Dimension / 10, Y , Dimension / 10, Dimension 'Linke Seite

DrawRect X , Y , Dimension , Dimension / 10 'Ober Seite
DrawRect X , Y + Dimension - Dimension / 10, Dimension , Dimension / 10 'Unterseite
Rem
Kollisionsabfrage, wie auch schon beim Button. Hier gibt es allerdings einen kleinen Unterschied:
Das Feedback ist nicht in dieser Abfrage drin, sondern kommt erst später. Das hat den Grund,
dass ja ein Kreuz in die CheckBox gezeichnet wird, sofern die Checkbox aktiv ist. Die Kollisionsabfrage
wird aber sicher nicht die ganze Zeit erfüllt sein (vor allem dank MH1 ^^) und deswegen braucht man eine
zweite Schleife, die im Falle der "Aktivität" durchlaufen wird.
End Rem

If MH1 Then ' * Siehe unten
If MX > X And MX < X + Dimension
If MY > Y And MY < Y + Dimension
Box.active = Not Box.active
EndIf
EndIf
EndIf
Rem
Und hier haben wir den zweiten Part der Kollision. Diese Konstruktion wird in anderen Elementen ebenfalls
eingesetzt Wink
End Rem

If Box.active Then
SetLineWidth Dimension / 10
DrawLine X + Dimension / 5, Y + Dimension / 5, X + Dimension - Dimension / 5, Y + Dimension - Dimension / 5
DrawLine X + Dimension / 5, Y + Dimension - Dimension / 5, X + Dimension - Dimension / 5, Y + Dimension / 5
SetLineWidth 1
Feedback = 1
EndIf
Return Feedback
End Function



Rem
* Und jetzt kommt der Grund dafür, wieso ich Variablen für MouseX() usw. verwende (wenn man mal von der
Gewohnheit absieht Wink. Dazu solltest du die Zeile:

MH1= MouseHit(1)

... auskommentieren und folgendes ändern:

If MouseHit(1) Then '<- statt MH1
If MX > X And MX < X + Dimension
If MY > Y And MY < Y + Dimension
Box.active = Not Box.active
EndIf
EndIf
EndIf

Wenn du das getan hast und das Programm ausführst, wird dir sicherlich schnell auffallen, dass nur
eine CheckBox mit einem Kreuz versehen werden kann. Jetzt könntest du auch noch die Zeile
MH1 = MouseHit(1) wieder reinpacken, den Kollisionsteil aber beibehalten. In dem Fall kann man
nämlich keine CheckBox mehr aktivieren.

Ja, die Schuld liegt bei MouseHit(1). Benutzt man diese Funktion, so wird nur der erste Klick erkannt.
Für weitere Informationen: https://www.blitzforum.de/forum/viewtopic.php?p=253180#253180

Und das wars mit der CheckBox :)

-----------------------------------------------------------------------------------------------------------------------------------

Radiobox

BlitzMax: [AUSKLAPPEN]


Rem
Die RadioBox funktioniert größtenteils wie die CheckBox. Es gibt nur den unterschied, dass
RadioBoxen in Gruppen vorhanden sind und innerhalb der Gruppe kann nur eine aktiv sein.
Ansonsten kommt es auf das selbe hinaus, sodass der Großteil des Codes der CheckBox
ähnlich ist. Los gehts ->
End Rem

SuperStrict
'-------------------------------
'Unsere Variablen
'-------------------------------
Global GW:Short, GH:Short
Global MX:Short, MY:Short, MH1:Byte

Global RadioBoxList:TList = New TList 'Liste für die RadioBoxen
Global RadioBoxCount:Byte 'Auch die RadioBoxen wollen gezählt werden :)
'-------------------------------
'Types
'-------------------------------
'Hat fast die selben Punkte, abgesehen von "Group", da sich die Box in einer Gruppe befindet.
Type TRadioBox
Field active:Byte
Field ID:String
Field Group:Byte

Method New:TRadioBox()
RadioBoxCount = RadioBoxCount + 1
End Method
End Type
Global Radio:TRadioBox
'-------------------------------
GW = 800
GH = 600
Graphics GW, GH, 0, 60
SetClsColor 60, 60, 60
'-------------------------------
'HauptSchleife
'-------------------------------
Repeat
Cls
MX = MouseX()
MY = MouseY()
MH1= MouseHit(1)

'Gruppe 0
If RadioBox(100, 50 ) Then Print "RadioBox 1 | Gruppe 0"
If RadioBox(100, 100 ) Then Print "RadioBox 2 | Gruppe 0"
If RadioBox(100, 150 ) Then Print "RadioBox 3 | Gruppe 0"
If RadioBox(100, 200 ) Then Print "RadioBox 4 | Gruppe 0"

'Gruppe 1
If RadioBox(200, 50, 1) Then Print "RadioBox 1 | Gruppe 1"
If RadioBox(200, 100, 1) Then Print "RadioBox 2 | Gruppe 1"
If RadioBox(200, 150, 1) Then Print "RadioBox 3 | Gruppe 1"
If RadioBox(200, 200, 1) Then Print "RadioBox 4 | Gruppe 1"

Flip
Until AppTerminate() Or KeyDown(KEY_Escape)
End
'-------------------------------
'Unsere Funktionen'
Function RadioBox:Byte(X:Short, Y:Short, Group:Byte = 0)
Local Dimension:Byte = 30, ID:String 'Siehe CheckBox Wink
Local Varification: Byte, Feedback:Byte 'Siehe CheckBox Wink
Local Red:Int, Green:Int, Blue:Int 'Variablen für die Hintergrundfarbe

ID = String (X) + String (Y)
'Wie auch bei der CheckBox wird nun dafür gesorgt, dass der richtige Type zur Verfügung steht.
If Radio:TRadioBox = Null Then
Radio:TRadioBox = New TRadioBox
ListAddLast( RadioBoxList, Radio )
Radio.ID = ID
Radio.Group = Group 'Eine RadioBox bekommt neben dem Namen auch noch die Gruppe (/Familie^^) spendiert.
Else
For Radio:TRadioBox = EachIn RadioBoxList
If Radio.ID = ID Then Exit
Varification = Varification + 1
Next
If Varification = RadioBoxCount Then
Radio:TRadioBox = New TRadioBox
ListAddLast( RadioBoxList, Radio )
Radio.ID = ID
Radio.Group = Group
EndIf
EndIf

'Die Zeichnung unserer RadioBox:
SetColor 255, 255, 255
DrawOval X, Y, Dimension, Dimension 'Äußerer Kreis

Rem
Nun kommt der Einsatz für die drei Farbvariablen am Anfang. Es wird gleich ein Kreis in der Mitte
des ersten Kreises gezeichnet, damit dieser ungefühlt aussieht.
Die Farbe der Innenseite sollte entsprechend die des Hintergrundes sein und mit GetClsColor bekommt
man sie raus.
End Rem

GetClsColor( Red, Green, Blue )
SetColor Red, Green, Blue
DrawOval X + Dimension / 10, Y + Dimension / 10, Dimension - Dimension / 5, Dimension - Dimension / 5
Rem
Da RadioBoxen für gewöhnlich rund sind, so wie auch die dieser Funktion, brauchen sie eine andere
Kollisionserkennung. In dem Fall macht man das mit dem Pythagoras.
Mit Hilfe des Pythagoras wird die Hypothenuse errechnet (Wir gehen vom Kreis/Radioboxen Mittelpunkt aus).
Wenn die Hypothenuse kürzer, oder genauso lang ist, wie der Radius (Dimension / 2), dann findet eine
Kollision statt.

Ansonsten ist es wieder die doppelabfrage, die ich schon bei der Checkbox genutzt habe.
End Rem

If MH1 Then
If Sqr( (MX - X - Dimension / 2 ) * ( MX - X - Dimension / 2) + (MY - Y - Dimension / 2) * ( MY - Y - Dimension / 2) ) < Dimension / 2 Then
Radio.active = Not Radio.active
EndIf
EndIf

If Radio.active Then
'Aktivierungskreis zeichnen, Rückgabewert einsetzen...
SetColor 255, 255, 255
DrawOval X + Dimension / 5, Y + Dimension / 5, Dimension - Dimension / 2.5, Dimension - Dimension / 2.5
Feedback = 1
Rem
Und hier der Unterschied zur CheckBox: Wenn ich die RadioBox aktiviere, dann müssen alle anderen in der selben
Gruppe deaktiviert werden (bzw. eigentlich kann ja dadurch nur einer aktiv sein, sodass auch höhstens einer deaktiviert werden
kann, aber so ist es nun mal einfacher ^^). Deswegen muss man nun alle nochmal durchgehen, anhand des Namens
dafür sorgen, dass nicht die momentane RadioBox deaktiviert wird und den Rest deaktiveren.
Fertig ist die RadioBox :D
End Rem

For Radio:TRadioBox = EachIn RadioBoxList
If Radio.ID <> ID Then
If Radio.Group = Group Then
Radio.active = 0
EndIf
EndIf
Next
EndIf
Return Feedback
End Function


-----------------------------------------------------------------------------------------------------------------------------------

DropDown Menu

BlitzMax: [AUSKLAPPEN]

Rem
Nun wird das ganze etwas länger sein. Deswegen habe ich ein paar
Sachen (kosmetischer Natur) weggelassen. Hier ist ersteinmal
das Prinzip wichtig. Den Rest kannst du beim ResolutionDropDownMenu
nachlesen. Da steht ist der ausgelassene Teil drin + Extras :)

Noch eine Sache vorab: Das fällt nun vor allem bei dem DropDownMenu
auf; man muss entscheiden, wie "freundlich" der Code ist. Das ist
wohl das falsche Wort, aber ich meine damit, dass die Elemente
alle sehr viel effizienter sind, wenn man die Sachen vorher berechnen
lässt, zumindest die allgemeinen Sachen.
Auch das wird im ResolutionDropDownMenu deutlich.
End Rem

SuperStrict
'-------------------------------
'Unsere Variablen
'-------------------------------
'wie immer...
Global GW:Short, GH:Short
Global MX:Short, MY:Short, MH1:Byte

Global DropDownList:TList = New TList
Global DropDownCount:Byte
'-------------------------------
'Types
'-------------------------------
Rem
Hier nun einige Neuerungen. Ein DropDownMenu sollte für gewöhnlich
einen Text enthalten. In dem Fall ersetze ich das durch die ID und
somit muss ich keine Namensgebung erzwingen.

Außerdem hat man bei einem DropDownMenu eine gewisse Auswahl und
je nachdem, was man nun auswählt, sieht man dies entsprechend innerhalb
des zugeklappten Menüs. Das wäre in dem Fall "ActualText". Chosen
dagegen speichert die Auswahl in Form einer Zahl.
Damit weiß man dann, dass der Nutzer z.B. den 2. Punkt ausgewählt hat.

Man könnte das weg lassen und alles durch ActualText lösen,
aber das wäre etwas umständlicher. Der Rest bleibt beim alten.
End Rem

Type TDropDownMenu
Field active: Byte
Field Text: String
Field Chosen: Byte
Field ActualText:String
Method New:TDropDownMenu()
DropDownCount = DropDownCount + 1
End Method
End Type
Global DropDown:TDropDownMenu
'-------------------------------
GW = 800
GH = 600
Graphics GW, GH, 0, 60
SetClsColor 60, 60, 60
'-------------------------------
'HauptSchleife
'-------------------------------
Repeat
Cls
MX = MouseX()
MY = MouseY()
MH1= MouseHit(1)

Rem
Diesmal ist schon eine Select Case Abfrage nötig.
Der Inhalt des Menü´s ist diesmal (im Gegensatz zur
RadioBox) nicht durchsichtig / hat nicht die selbe Farbe,
wie der Hintergrund.

Außerdem sind die Menü Punkte nicht mittig ausgerichtet und
die Maße des Menüs werden nicht angepasst. Wie gesagt
ändert sich das bei der Resolution Version.
End Rem

Select DropDownMenu (" 1; 2; 3; 4; 5", 50, 50)
Case 1
Print 1
Case 2
Print 2
Case 3
Print 3
Case 4
Print 4
Case 5
Print 5
End Select

Select DropDownMenu (" 6; 7; 8; 9;10",250, 50)
Case 1
Print 6
Case 2
Print 7
Case 3
Print 8
Case 4
Print 9
Case 5
Print 10
End Select

Select DropDownMenu ("Hallo;Hallo2;...",450, 50)
Case 1
Print "Hallo"
Case 2
Print "Hallo2"
Case 3
Print "..."
End Select

Flip
Until AppTerminate() Or KeyDown(KEY_Escape)
End
'-------------------------------
'Unsere Funktionen'
Rem
Jetzt geht es an die Funktionen, aber diesmal ist noch eine zusätzliche Funktion
nötig, denn ein DropDownMenu bekommt mehrere Paramenter in Form von Text eingespeißt
und da diese Parameter variabel sind (zumindest in dem Fall - ist so auch praktischer),
muss man sich eines Tricks bedienen. Man nehme ein Trennzeichen (ich habe mich für das
Semikolon entschieden) und damit werden dann die Parameter getrennt.

Nun muss aber noch herausgefunden werden, wie viele Parameter es nun sind, bzw. wie viele
Trennzeichen es sind (Parameteranzahl = Trennzeichen + 1) und dafür habe ich hier eine
Zusatzfunktion, die einen Text nach Zeichen durchsucht und ausgibt wie viele gefunden wurden.

Die Funktion wird auch in anderen GUI Elementen auftauchen Wink
End Rem

Function LetterCount:Byte(txt:String, Letter:String)
Local Lenght:Byte, Count:Byte, LetterT:String 'Länge des Textes, Anzahl des ausgewählten Buchstaben im Text und der
'momentan ausgewählte Buchstabe.
Lenght = Len(txt)
For Local i:Byte = 0 To Lenght 'Der Text wird durchgegangen
LetterT = Mid(txt, i, 1) 'Jedes Zeichen wird zwischen gespeichert...
If LetterT = Letter Then 'Des momentane Zeichen wird mit dem Parameter "Letter" verglichen
Count = Count + 1 'und wenn es dasselbe Zeichen ist, wird gezählt
EndIf
Next
Return Count 'Die Anzahl wird zurückgeliefert
End Function

Function DropDownMenu:Byte ( txt:String, X:Short, Y:Short )
Local Width: Short, Height: Byte 'Höhe und Breite... wie immer
Rem
Text ist eine Übergabe Variable. Während txt den Kompletten String speichert,
enthält Text nur ein Wort von diesem String.
End Rem

Local Text: String
Rem
WordCount speichert die Anzahl der Wörter, die in txt drin stecken.
WordPoint und SecondPoint speichern die Punkte, zwischen denen
das nächste Wort ist.
End Rem

Local SecondPoint: Byte, WordCount: Byte, WordPoint: Byte
Local Varification:Byte 'Siehe Checkbox usw...

'Auswahl des richtigen Types... wie gewohnt.
If DropDown:TDropDownMenu = Null Then
DropDown = New TDropDownMenu
ListAddLast( DropDownList, DropDown )
DropDown.Text = txt
Else
For DropDown:TDropDownMenu = EachIn DropDownList
If DropDown.Text = txt Then Exit
Varification = Varification + 1
Next
If Varification = DropDownCount Then
DropDown:TDropDownMenu = New TDropDownMenu
ListAddLast( DropDownList, DropDown )
DropDown.Text = txt
EndIf
EndIf
'Höhe und Breite...
Width = 150
Height = 30
'DropDownMenu zeichnen
SetColor 255, 255, 255
DrawRect X, Y, Width, Height 'äußeres Rechteck
SetColor 0, 0, 0
DrawRect X + Width * 0.05, Y + Height * 0.05, Width - Width * 0.1 , Height - Height * 0.1 'inneres Rechteck

SetColor 255, 255, 255
DrawRect X + Width, Y, Height, Height 'äußeres Aktivierungsfeld
SetColor 0, 0, 0
DrawRect X + Width, Y + Height * 0.05, Height - Height * 0.1, Height - Height * 0.1 'inneres Aktivierungsfeld

'Kollision mit demselben Prinzip wie schon beim Button
If MH1 Then
If MX > X + Width And MX < X + Width + Height
If MY > Y And MY < Y + Height
DropDown.active = Not DropDown.active
EndIf
EndIf
EndIf

If DropDown.active Then
WordCount = LetterCount ( txt, ";" ) 'Anzahl der Wörter, die wir zur Auswahl haben
'Kollisionserkennung
If MH1 Then
If MX > X And MX < X + Width + Height Then
If MY > Y + Height And MY < Y + Height + (WordCount + 1) * TextHeight(txt) Then
Rem
Und hier ist der 2. Teil der Kollisionsbestimmung, denn wenn man von der Y Koordinate
der Maus die Position des Textes, der zur Auswahl steht, abzieht und das durch die
Texthöhe teilt, dann bekommt man die momentane Auswahl.
End Rem

DropDown.Chosen = ( MY - Y - Height - Height / 5) / TextHeight(txt) + 1
DropDown.active = Not DropDown.active 'DropDownMenu wird zugeklappt.
EndIf
EndIf
EndIf
'Das ausgeklappte Auswahlmenü
SetColor 255, 255, 255
DrawRect X, Y + Height, Width + Height, 300 'Äußeres Feld
SetColor 0, 0, 0
DrawRect X + Height / 10, Y + Height * 1.1, Width + Height - Height / 5, 300 - Height / 5 'Inneres Feld

Rem
Im Folgenden geht es darum alle Wörter herauszufinden, die im Ausgeklappten
Menü geschrieben werden sollen. Dafür wird zuerst ein Semikolon vorne am
Text hinzugefügt. Dann wird die Stelle rausgesucht, wo das erste Semikolon steht
(im ersten Durchgang wäre das 0, da ich jetzt vorne ein Semikolon hinzugefügt habe).

Danach wird von dieser gefunden Stelle aus das nächste Semikolon gesucht. Zwischen
diesen beiden Stellen liegt das erste Wort. Das wird rausgeschnitten und gezeichnet.

Der Schritt mit dem rangehängtem Semikolon ist nötig, da sonst das erste
Wort nicht auftauchen würde.
End Rem

txt = ";" + txt
For Local i:Byte = 0 To WordCount
WordPoint = Instr(txt,";", SecondPoint)
SecondPoint = Instr(txt,";", WordPoint + 1)
Text = Mid( txt, WordPoint + 1, SecondPoint - 1 - WordPoint )
SetColor 255, 255, 255
DrawText Text, X + Width / 10, Y + Height + Height / 5 + TextHeight(txt) * i
Rem
Hier wird nun mit Hilfe der Auswahl, die ja als Zahl in "DropDown.Chosen"
gespeichert wird, der Text innerhalb der Box herausgefunden.
End Rem

If i = DropDown.Chosen - 1 Then
DropDown.ActualText = Text
EndIf
Next
EndIf

SetColor 255, 255, 255
'Die Auswahl wird eingetragen - und zwar zentriert in der Box
DrawText DropDown.ActualText, X + (Width - TextWidth(DropDown.ActualText)) / 2, Y + (Height - TextHeight(DropDown.ActualText)) / 2
Return DropDown.Chosen 'Die Auswahl wird zurückgegeben
End Function

-----------------------------------------------------------------------------------------------------------------------------------

InputBox


mfG Seven
  • Zuletzt bearbeitet von Seven am Sa, Jun 02, 2012 15:44, insgesamt 6-mal bearbeitet

BladeRunner

Moderator

BeitragSo, Mai 20, 2012 8:48
Antworten mit Zitat
Benutzer-Profile anzeigen
zum einen: schön geschrieben.
zum andern: ein wenig Kritik muss dennoch sein.
- Du erwähnst dass Du globale später in einen Type auslagern willst. Wenn Du diesen (komplett korrekten) Fakt schon anführst könntest Du es eigentlich auch direkt machen. Um genau zu sein hätte ich die GUI-Elemente direkt als Klasse angelegt, denn späteres umbauen wird deine Leser eher verwirren.

- mehr beiläufig erwähnst Du dass Du mousex() etc. in Variablen packst weil es "sonst zu Fehlern komme" - hier wäre für den geneigten Leser eine Erläuterung schön (immerhin willst Du ja Wissen ver4mitteln).

-ich möchte dir nahelegen noch kurz eine Rechtschreibeprüfung über dienen Text laufen zu lassen, da sind noch ein paar Schnitzer drin, und ein Tutorial lebt ja auch mit von der äußeren Form.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

Seven

BeitragSo, Mai 20, 2012 14:04
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für Kritik Smile

1. Ich schätze ich sollte wirklich mehr in die Richtung gehen. Das sind noch Überbleibsel aus BlitzBasic,
aber ok. Das dürfte den Code verringern.

2. Das habe ich jetzt gemacht. Wobei ich sagen muss, dass ich nicht wusste, warum dieser Fehler
zustande kommt.

3. Ich habe es nochmal durchgelesen und ein paar Sachen korrigiert.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group