Ich hab mich endlich mal an eine GUI gesetzt, da ich gemerkt habe dass sowas auf Dauer doch praktischer ist.
Das ganze war dann jetzt im Endeffekt keine Hexerei und es ist auch nichts großartiges, aber vielleicht werden sich ja einige Neulinge drüber freuen.
Ich schieb noch nen type zum verwalten von Bildern hinterher, alleinschon weil er in der GUI gebraucht wird.
Die GUI beinhaltet: Windows (keine eigenständigen Fenster, sondern nur Gruppenverbände)
Labels. Das sind einfach größere Flächen die Buttons beinhalten. So kann man unterschiedliche Flächen bequem ein und ausblenden. Natürlich Buttons. Und Textfelder zur Texteingabe. Wie das mit der Texteingabe funktioniert ist unten im Beispiel zu sehen.
Also, erstmal, hier der BIldertype:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TMyIMage Global tlAllMyImages:TList = New TList Field tiimage:TImage Field iMaxFrames:Int Field iFrame:Int Field iTimer:Int, iLastFrameUpDate:Int Function Create:TMyImage(pImage:TImage, pMaxFrames:Int = 0, PTimer:Int = 0) Local MyIMage:TMyImage = New TMyImage MyIMage.tiimage = pImage MyIMage.iMaxFrames = pMaxFrames MyIMage.iTimer = PTimer MyIMage.iFrame = 0 MyIMage.iLastFrameUpDate = MilliSecs() Return Myimage End Function Method Animate() If iMaxFrames <> 0 Then If ((iTimer + iLastFrameUpDate) < MilliSecs()) Then iFrame = (iFrame + 1) Mod iMaxFrames iLastFrameUpDate = MilliSecs() EndIf End If End Method Method AnimateManual() If iMaxFrames <> 0 Then iFrame = (iFrame + 1) Mod iMaxFrames End If End Method Method New() tlAllMyImages.AddLast(Self) End Method Method Destroy() tlAllMyImages.Remove(Self) End Method End Type
Und hier das ganze GUI Gedöhns:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Global CurrentWindow:TGuiElement Global SelectedTextField:TGuiElement
Const iGUITYPE_WINDOW:Int = 1 Const iGUITYPE_LABEL:Int = 2 Const iGUITYPE_BUTTON:Int = 3 Const iGUITYPE_TEXTFIELD:Int = 4
Const iBUTTONWIDTH:Int = 128 Const iBUTTONHEIGHT:Int = 64
Const iMAX_LABELS_PER_WINDOW:Int = 5 Const iMAX_BUTTONS_PER_LABEL:Int = 10
AutoMidHandle(1)
Global tiButton:TImage = LoadAnimImage("Data/gfx/GUI/ButtonComplete.png", 128, 64, 0, 2) Global tifGUIFont:TImageFont = LoadImageFont("Data/gfx/GUI/chintzy.ttf", 17, SMOOTHFONT) Global tiTextField:TImage = LoadImage("Data/gfx/GUI/InBox.png")
Type TGuiElement Global tlAllGuiElements:TList = New TList Field Owner:TGuiElement Field aChildren:TGuiElement[] Field iType:Int Field sName:String Field iXPos:Int, iYPos:Int Field iWidth:Int, iHeight:Int Field iEnabled:Int Field iVisible:Int = 1 Field tmImage:TmyImage Field iClicked:Int Field iClickedLast:Int Field iIsOn:Int, iIsOnLast:Int Field iLastBlink:Int, iBlinkTime:Int Field iBlink:Int Field sInput:String Function CreateWindow:TGuiElement() Local Window:TGuiElement = New TGuiElement Window.Owner = Null Window.iType = iGUITYPE_WINDOW Window.aChildren = New TGuiElement[iMAX_LABELS_PER_WINDOW] For Local index:Int = 0 To (iMAX_LABELS_PER_WINDOW - 1) Window.aChildren[index] = Null Next Return Window End Function Function CreateLabel:TGuiElement(pWindowOwner:TGuiElement, penabled:Int = 1) Local Label:TGuiElement = New TGuiElement Label.Owner = pWindowOwner InsertInWindow(Label, pWindowOwner) Label.iType = iGUITYPE_LABEL Label.iEnabled = penabled Label.aChildren = New TGuiElement[iMAX_BUTTONS_PER_LABEL] For Local index:Int = 0 To (iMAX_BUTTONS_PER_LABEL - 1) Label.aChildren[index] = Null Next Return Label End Function Function CreateButton:TGuiElement(pLabelOwner:TGuiElement, psName:String, piXPos:Int, piYPos:Int, piWidth:Int = iBUTTONWIDTH, piHeight:Int = iBUTTONHEIGHT, piEnabled:Int = 1) Local Button:TGuiElement = New TGuiElement Button.Owner = pLabelOwner Button.iType = iGUITYPE_BUTTON InsertInLabel(Button, pLabelOwner) Button.sName = psName Button.iXPos = piXPos Button.iYPos = piYPos Button.iWidth = piWidth Button.iHeight = piHeight Button.iEnabled = piEnabled Button.tmImage = TMyIMage.Create(tiButton, 2) Return Button End Function Function CreateTextField:TGuiElement(pLabelOwner:TGuiElement, psName:String, piXPos:Int, piYPos:Int, piWidth:Int = iBUTTONWIDTH, piHeight:Int = iBUTTONHEIGHT, piEnabled:Int = 1) Local TextField:TGuiElement = New TGuiElement TextField.Owner = pLabelOwner TextField.iType = iGUITYPE_TEXTFIELD InsertInLabel(TextField, pLabelOwner) TextField.iXPos = piXPos TextField.iYPos = piYPos TextField.iWidth = piWidth TextField.iHeight = piHeight TextField.iEnabled = piEnabled TextField.iBlinkTime = 500 TextField.iBlink = 1 TextField.iLastBlink = MilliSecs() TextField.tmImage = TMyIMage.Create(tiTextField) TextField.sName = psName Return TextField End Function Function InsertInWindow(pLabel:TGUIElement, pWindow:TGuiElement) For Local iIndex:Int = 0 To (iMAX_LABELS_PER_WINDOW - 1) If (pwindow.aChildren[iIndex] = Null) Then pwindow.aChildren[iIndex] = plabel Return EndIf Next End Function Function InsertInLabel(pButton:TGUIElement, pLabel:TGuiElement) For Local iIndex:Int = 0 To (iMAX_BUTTONS_PER_LABEL - 1) If (pLabel.aChildren[iIndex] = Null) Then pLabel.aChildren[iIndex] = pButton Return EndIf Next End Function Function GuiElementClicked:Int(pGuiElement:TGuiElement) Return pGuielement.iclicked End Function Method New() tlAllGuiElements.AddLast(Self) End Method End Type
Function SetActiveWindow(pWindow:TGuiElement) If pWindow.iType = iGUITYPE_WINDOW Then CurrentWindow = pWindow EndIf End Function
Function UpdateGUI(piMousehit:Int, pfMouseX:Int, pfMouseY:Int) For Local GuiElement:TGuiElement = EachIn TGuiElement.tlallGuiElements Select guielement.iType Case iGUITYPE_LABEL If GuiElement.ienabled And GUIElement.iVisible And (GUIElement.Owner = CurrentWindow) Then GuiElement.iClickedLast = GuiElement.iclicked guielement.iisonlast = guielement.iison GuiElement.iClicked = (RectMouseCollision(pfmousex, pfmousey, GUIElement.iXPos, GUIElement.iYPos, GUIElement.iWidth, GUIElement.iHeight) And piMouseHit) guielement.iison = RectMouseCollision(pfmousex, pfmousey, GUIElement.iXPos, GUIElement.iYPos, GUIElement.iWidth, GUIElement.iHeight) Else GuiElement.iClicked = 0 EndIf Case iGUITYPE_BUTTON If GuiElement.ienabled And GuiElement.iVisible And (GuiElement.Owner.owner = CurrentWindow) Then If GuiElement.Owner.iEnabled Then GuiElement.iClickedLast = GuiElement.iclicked guielement.iisonlast = guielement.iison GuiElement.iClicked = (RectMouseCollision(pfmousex, pfmousey, GUIElement.iXPos, GUIElement.iYPos, GUIElement.iWidth, GUIElement.iHeight) And piMouseHit) GuiElement.iison = RectMouseCollision(pfMouseX, pfMouseY, GuiElement.iXPos, GuiElement.iYPos, GuiElement.iWidth, GuiElement.iHeight) Else GuiElement.iClicked = 0 EndIf EndIf Case iGUITYPE_TEXTFIELD If GuiElement.ienabled And GuiElement.iVisible And (GuiElement.Owner.owner = CurrentWindow) Then If GuiElement.Owner.iEnabled Then guiElement.iClickedLast = GuiElement.iclicked guielement.iisonlast = guielement.iison GuiElement.iClicked = (RectMouseCollision(pfmousex, pfmousey, GUIElement.iXPos, GUIElement.iYPos, GUIElement.iWidth, GUIElement.iHeight) And piMouseHit) GuiElement.iison = RectMouseCollision(pfMouseX, pfMouseY, GuiElement.iXPos, GuiElement.iYPos, GuiElement.iWidth, GuiElement.iHeight) Else GuiElement.iClicked = 0 EndIf EndIf End Select Next End Function
Function RenderGui() For Local GuiElement:TGuielement = EachIn TGuiElement.tlAllGuiElements Select GuiElement.iType Case iGUITYPE_BUTTON If GuiElement.iVisible And (GuiElement.Owner.owner = CurrentWindow) Then If GuiElement.Owner.iEnabled Then If GuiElement.iison <> GuiElement.iisonlast Then GuiElement.tmimage.animateManual() Local ImageFont:TimageFont = GetImageFont() SetImageFont(tifGuiFont) SetScale(Float(GuiElement.iwidth) / Float(ImageWidth(GuiElement.tmimage.tiimage)), Float(GuiElement.iheight) / Float(ImageHeight(GuiElement.tmimage.tiimage))) DrawImage(GuiElement.tmimage.tiimage, GuiElement.iXPos, GuiElement.iYPos, GuiElement.tmimage.iframe) SetColor(20, 20, 20) DrawText(GuiElement.sName, GuiElement.iXPos - TextWidth(GuiElement.sname) / 2, GuiElement.iYPos - TextHeight(GuiElement.sname) / 2) SetColor(255, 255, 255) SetScale(1, 1) SetImageFont(ImageFont) EndIf EndIf Case iGUITYPE_TEXTFIELD If GuiElement.iVisible And (GuiElement.Owner.owner = CurrentWindow) Then If GuiElement.Owner.iEnabled Then If ((guielement.iblinktime + guielement.ilastblink) < MilliSecs()) Then guielement.ilastblink = MilliSecs() guielement.iblink = 1 - guielement.iblink End If If GuiElement.iison <> GuiElement.iisonlast Then GuiElement.tmimage.animateManual() Local ImageFont:TimageFont = GetImageFont() SetImageFont(tifGuiFont) DrawImage(GuiElement.tmimage.tiimage, GuiElement.iXPos, GuiElement.iYPos, GuiElement.tmimage.iframe) SetColor(20, 20, 20) DrawText(GuiElement.sName, GuiElement.iXPos - guielement.tmImage.tiimage.width / 3, GuiElement.iYPos - guielement.tmImage.tiimage.height / 2) SetColor(255, 255, 255) SetScale(1, 1) SetImageFont(ImageFont) SetColor(200, 150, 150) DrawText(guielement.sinput, GuiElement.iXPos - 50, GuiElement.iyPos - 5) SetColor(255, 255, 255) If SelectedTextField = GuiElement If GuiElement.iblink = 1 Then DrawRect(GuiElement.iXPos - 50 + TextWidth(GuiElement.sinput), GuiElement.iyPos - 5, 1, 15) End If EndIf EndIf EndIf End Select Next End Function
Function RectMouseCollision:Int(piMouseX:Int, piMouseY:Int, piXRect:Int, piYRect:Int, piRectWidth:Int, piRectHeight:Int) If ((piMouseX <= (piXRect + piRectWidth / 2)) And (piMouseX >= (piXRect - piRectWidth / 2))) Then If ((piMouseY <= (piYRect + piRectHeight/2)) And (piMouseY >= (piYRect - piRectHeight/2))) Then Return True EndIf EndIf Return False End Function
Den Pfad für die Grafiken muss natürlich jeder individuell umschreiben. UNd die Konstanten für die Buttongrößen dann entsprechend anpassen.
Die Struktur sieht so aus: Es kann beliebig viele Windows geben. Jedes window kann maximal 5 Labels (kleinere Flächen) beinhalten und jedes Label kann maximal 10 Buttons beinhalten. Ihr könnt also auf einem einzigen Fenster gleichzeitig 50 Buttons darstellen. Es kann immer nur ein Fenster aktiv sein.
Welches das ist ändert mal einfach mit SetActiveWindow(pWindow).
Beim erstellen von Labels ist es wichtig, ein Fenster (Window) zu übergeben das vorher auch bereits erstellt wurde. Beim Erstellen eines Buttons muss man ein entsprechendes Label angeben.
Hier ist noch ein Beispiel:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Import brl.timer Import brl.random Import brl.PNGLoader Import "GUI_New.bmx" SuperStrict
Graphics 1024, 768
SeedRnd MilliSecs() AutoMidHandle(1) SetBlend(ALPHABLEND)
Global fGFXWidth:Float = GraphicsWidth() Global fGFXHeight:Float = GraphicsHeight() Global fGFXWidthHalf:Float = fGFXWidth / 2.0 Global fGFXHeightHalf:Float = fGFXHeight / 2.0
Global fXScroll:Float, fYScroll:Float
Global FTimer:TTimer = CreateTimer(60)
Global iMousehitRight:Int Global iMousehitLeft:Int Global iMouse_X:Int, iMouse_Y:Int
Local MainMenuWindow:TGuiElement = tguielement.createwindow() Local OptionLabel:TGuiElement = tguielement.CreateLabel(MainMenuWindow, 0) Local MenuLabel:TGuiElement = tguielement.CreateLabel(MainMenuWindow) Local StartingGameLabel:TGuiElement = TGuiElement.CreateLabel(MainMenuWindow, 0)
Local ButtonOptionsMenu:TGuiElement = TGuiElement.CreateButton(MenuLabel, "Options", 400, 200,,, 1) Local ButtonBeendenMenu:TGuiElement = TGuiElement.CreateButton(MenuLabel, "Beenden", 400, 300,,, 1) Local ButtonStartenMenu:TGuiElement = TGuiElement.CreateButton(MenuLabel, "Starten", 400, 400,,, 1) Local ButtonMenuOptions:TGuiElement = TGuiElement.CreateButton(OptionLabel, "Menu", 300, 300,,, 1)
Local TextFieldPLayerName:TGuiElement = TGuielement.CreateTextField(Startinggamelabel, "Name:", 400, 300,,, 1)
SetActiveWindow(MainMenuWindow)
While Not KeyHit(KEY_ESCAPE) Or AppTerminate() WaitTimer(FTimer) Cls iMouse_x = MouseX() iMouse_Y = MouseY() iMousehitLeft = MouseHit(1) UpdateGUI(iMousehitLeft, iMouse_X, iMouse_Y) RenderGui() If iMousehitLeft And TGuiElement.guielementclicked(ButtonOptionsMenu) Then OptionLabel.ienabled = 1 MenuLabel.iEnabled = 0 EndIf If iMousehitLeft And TGuiElement.guielementclicked(ButtonBeendenMenu) Then End If iMousehitLeft And TGuiElement.GuiElementClicked(ButtonStartenMenu) Then MenuLabel.iEnabled = 0 StartingGameLabel.ienabled = 1 EndIf If iMousehitLeft And TGuiElement.GuiElementClicked(ButtonMenuOptions) Then OptionLabel.ienabled = 0 MenuLabel.iEnabled = 1 EndIf If iMousehitLeft And TGuiElement.GuiElementClicked(TextFieldPLayerName) Then SelectedTextField = TextFieldPLayerName If SelectedTextField <> Null Then Local c:Int Local w:String c = GetChar() If ((c <> 13) And (c <> 0)) Then If c <> 8 Then w = Chr(c) ElseIf c = 8 Then SelectedTextField.sinput = Left(SelectedTextField.sinput, SelectedTextField.sinput.Length - 1) EndIf EndIf If (SelectedTextField.ixpos - 50 + TextWidth(SelectedTextField.sinput)) < (SelectedTextField.iXPos + SelectedTextField.tmImage.tiimage.width / 2 - 30) Then SelectedTextField.sInput = SelectedTextField.sInput + w EndIf EndIf
imousehitleft = 0 Flip 0 Wend
So...
Viel Spaß damit. Ich hoffe es hilft mal jemandem.
Lg, M0rgenstern
|