GUI Gadget Tutorial
Übersicht

![]() |
MidimasterBetreff: GUI Gadget Tutorial |
![]() Antworten mit Zitat ![]() |
---|---|---|
Dieses Tutorial wird darstellen, wie man eine verschachtelte GUI 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 von verschiedene Displaygrößen sein.
Hier mal ein erster Blick drauf. Im Monkey-Forum-Codearchiv gibt es übrigens das gesamte Tutorial nochmal für die Sprache Monkey. 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/forum...hp?t=33457 . Fragen von Hilfesuchenden bitte hierhin https://www.blitzforum.de/forum/viewforum.php?f=29 und auf keinen Fall in diesen Thread. 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 |
||
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe |
![]() |
Midimaster |
![]() Antworten mit Zitat ![]() |
---|---|---|
Kapitel 1: Alles Gadget, oder was?
Zunächst starten wir wie üblich... Tja, und hier zweifle ich, wie ich's schreiben soll. Seit ich Monkey habe könnte man auch mal unüblich starten. Doch das ist heute nicht das Thema. BlitzMax: [AUSKLAPPEN] SuperStrict ...fast wie gewöhnlich... Die Repeat-Schleife ist sehr kurz und soll es auch so bleiben. Durch die zwei Funktionsaufrufe sollen alle grafikrelevanten Aktionen von den Update-Aktionen getrennt werden. Es gibt schon die Klasse Gadget, die später die GUI darstellt, es gibt dort auch schon Funktionen, die vom Hauptprogramm 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." Es gibt eine Stringvariable Debug$, die ich mir jederzeit und überall im Code mit Text füllen kann. Das hat sich so bewährt. Ein Beispiel sieht man bem Gadget.Draw(). Die Variable MausIn% wird später enthalten, welches GUI-Element geklickt wurde. Die Elemente der GUI selbst werden aus immer dem gleichen Typen bestehen. Wir nennen es TGadget. Es kann Frame und Label sein, Button und Ceckbox, Scrollfenster und Silder und, und und.... Jedes dieser Elemente hat eine eindeutige ID, an der es gefunden werden kann. Außerdem die Üblichen Werte wie X, Y, Breite, Höhe, ... Eine Variable Typ unterscheidet dann die Arbeitweise des Gadget. Die Elemente kommen in eine Liste. Wer zuerst rein kommt liegt optisch (z-Achse) zu unterst. Ein Element kennt seine Eltern, seine Kinder tragen sich später in die Children-Liste ein. So kennt es letztendlich auch seine Kinder. Daraus ergeben sich die ersten Fields, die unser Gadget haben muss: BlitzMax: [AUSKLAPPEN] Type TGadget nun kann man die ersten Gadgets erstellen: BlitzMax: [AUSKLAPPEN] Function OnCreate() Interessant dabei dürfte die Funktion Gadget:Gadget(Id%) sein. Sie findet ein Gadget aufgrund seiner Id-Nummer und gibt das Gadget zurück. In unserem Code wird dies bereits benutzt: Die Gadget.Create() sucht aufgrund einer ID-Zahl seine Mutter und hinterlegt sie in dem Feld Parent Wie ihr seht bleibt alles noch sehr abstrakt und völlig ohne Malen. Dies werde ich erst in Kapitel 2 zeigen. |
||
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:49, insgesamt 3-mal bearbeitet
![]() |
MidimasterBetreff: Kapitel 2: Mütter und Kinder |
![]() Antworten mit Zitat ![]() |
---|---|---|
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] Type TGadget 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 Viewport() ist eine Funktion, die den Malbereich auf ein Rechteckauschnitt beschränkt. Zunächst steht er für die Übermutter auf "unendlich". später werden die Gadgets ihre eigenen Grenzen so an die Kinder weiterreichen. Das Malen erfolgt in der Methode Gadget.DrawOne() Ist das Gadget nicht visible wird gleich abgebrochen und so auch die Kinder erst gar nicht gemalt. Zu den eigenen Koordinaten X Y werden die Koordinaten der Mutter offX offY addiert Hier wird der ViewPort auf seine neuen Grenzen eigestellt. Sind die Ausmaße des Gadget enger als der bisherige Viewport, werden diese Aumaße als zukünftige Grenze des Viewport festgesetzt: BlitzMax: [AUSKLAPPEN] If offX>sX Then sX=offX Die vorletzte Zeile erzwingt einen Abbruch des Malens, wenn der Viewport 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 Viewport, der aber um die Rahmenbreite verkleinert wird: BlitzMax: [AUSKLAPPEN] For Local loc:TGadget = EachIn Children 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] SuperStrict 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 die OnCreate() und OnUpdate() durch die Beispiele ersetzen. Mutter und Tochter wenn die Mutter bewegt wird geht die Tochter mit: BlitzMax: [AUSKLAPPEN] Function OnCreate() Fenstergrenzen Als Alternative bewegt Ihr mal Gadget 2. Tatsächlich sorgt die Gadget.Draw() bereits dafür, dass die Tochter nicht über die Mutter hinausgemalt wird: BlitzMax: [AUSKLAPPEN] Function OnUpdate() unterschiedliche Gadgets Oder ändert mal den "Typ". Sofort ändert sich die Farbe des Gadget: BlitzMax: [AUSKLAPPEN] ' die "0" ist der Typ: Z-Order: Wer überdeckt wen? Zwei Gadgets auf der selben Ebene. Das zuerst erstellt wird zu unterst gemalt: BlitzMax: [AUSKLAPPEN] Function OnCreate() Verschachtelung Mutter, Tochter, Enkel: BlitzMax: [AUSKLAPPEN] Function OnCreate() Ein Slider entsteht aus 4 Grundgadgets: BlitzMax: [AUSKLAPPEN] Function OnCreate() |
||
![]() |
MidimasterBetreff: Kapitel 3: Maus |
![]() Antworten mit Zitat ![]() |
---|---|---|
In diesem Kapitel werten wir die Aktionen aus, die in der GUI geschehen können. Hierfür brauchen wir weitere globale Parameter:
BlitzMax: [AUSKLAPPEN] Type TGadget Zunächst sehen die Funktionen TGadget.Check() und TGadget.CheckOne() den Draw()-Funktionen sehr ähnlich: BlitzMax: [AUSKLAPPEN] Function Check%() Die TGadget.Check() beginnt mit Check der Übermutter, die dann rekursiv alle ihre Kinder rufen wird. Vorher wird der Maus-Zustand festgestellt Die TGadget.CheckOne() erhält beim Aufruf wieder die Koordinaten der Mutter sowie den von ihr gesetzten Viewport. Die Tests und Berechnungen sind die gleichen wie bei Draw. Danach wird untersucht, ob die Maus sich innerhalb des Gadget befindet und die ID des Gadget gemerkt: BlitzMax: [AUSKLAPPEN] .... Nur wenn dies der Fall ist, werden auch die Kindern durchsucht. Wäre die Maus auch dort, würde dies vorgehen. Erst im letzten Moment vor der Rückgabe des Ergebnis wird geprüft, ob dem Gadget überhaupt erlaubt ist, Werte zu liefern. Anders als beim Malen, kann ja ein Disable Gadget Kinder enthalten, die Enabled sind. 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." Die Gadget.CheckOne() verweist bereits auf eine Scroll()-Funktion, die ich aber erst im Kapitel 4 vorstellen werde. Deshalb jetzt nur: BlitzMax: [AUSKLAPPEN] Method Scroll() Das Maus-Ereignis bekommt eine eigene Funktion, die in der Lage ist, ziehende Gesten von einfachen Punktberührungen zu unterscheiden: BlitzMax: [AUSKLAPPEN] Function MausAction() Die Funktion stellt die Werte MausX% MausY% und MausHit% zur Verfügung. MausHit% kennt dabei drei Zustände: 0=Maus nicht gedrückt 1=Maus ist gedrückt 2=Maus wurde an der selben Stelle losgelassen Bei Berührung spring MausHit zunächst auf 1 und springt beim Loslassen aber nur dann in den Zustand 2, wenn sich die Maus seitdem nicht allzuweit bewegt hat. Damit lässt sich "Ziehen" von "Klicken" unterscheiden. Abschließend wieder der gesamte Code. Man kann nun schon sehr schön in der Kondsole sehen, dass "Ziehen" zu keinen Clicks führt: BlitzMax: [AUSKLAPPEN] SuperStrict |
||
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group