Das Original befindet sich hier
Andorra 2D GUI
Teil 1 - Das GUI-System verwenden
Einleitung
http://andorra.sourceforge.net/tutots/guisample.jpg
Eigentlich alle professionellen Spiele verwenden nicht die Standardkomponenten, die Windows ihnen bietet, um das Benutzerinterface aufzubauen. Das
GUI-System sollte schließlich dem entsprechenden Spiel angepasst sein - eine Mittelaltersimulation profitiert sicherlich nicht von kunterbunten Windows XP Schaltflächen. Außerdem ist es schwierig die Standardkomponenten hardwarebeschleunigt darzustellen. Damit auch Sie entsprechend stimmige, voll in Ihr Spiel integrierte, GUIs erstellen können, liefert Andorra 2D ein recht leistungsfähiges und für die meisten Fälle genügendes
GUI-System mit. Dieses kann einfach über selbst geschriebene Komponenten erweitert werden und ist dazu noch voll Skinbar.
Bitte beachten Sie: Ein solches
GUI-System zu schreiben ist sehr zeitaufwendig - deshalb ist dessen Weiterentwicklung zugunsten der anderen Features von Andorra 2D momentan zurückgefahren. Wenn Sie selbst neue Komponenten entwickelt haben oder das System erweitern möchten, so schicken Sie mir einfach eine E-Mail.
Vorbereitungen
Zunächst müssen Sie sich eine entsprechene
GUI im mitgelieferten
GUI-Editor zusammenklicken, was ähnlich wie in Delphi funktioniert. Dabei sollten Sie jedes Formular einzeln als eine eigene
GUI-Datei (*.axg, Andorra
XML GUI) speichern.
Skins können ebenso mit dem mitgelieferten Skineditor erstellt werden, was momentan allerdings noch recht kompliziert ist. Es bietet sich an, die mitgelieferte Skindatei "sunna.axs" einfach umzubauen.
Außerdem benötigt eine Andorra
GUI noch eine Mauszeigerdefinitionsdatei. Erstellen Sie hierzu mit dem Imagelisteditor eine Bilderliste mit den entsprechenden Mauszeigern. Erstellen Sie anschließend eine einfache
XML Datei nach folgendem Beispiel, in dem Sie auf die einzelnen Einträge verweisen:
Delphi-Quellcode:
<?
xml version="1.0" encoding="iso-8859-1"?>
<
set>
<images source="cursors.ail"/>
<cursor name="default" src="default">
<hotspot x="0" y="0"/>
</cursor>
<cursor name="wait" src="wait">
<hotspot x="6" y="11"/>
<anim start="0" stop="7" speed="25"/>
</cursor>
<cursor name="cross" src="cross">
<hotspot x="8" y="8"/>
</cursor>
</
set>
Integration
Um nun die
GUI in einem Programm zu verwenden, brauchen wir zunächst einige Units:
In "AdGUI" befindet sich das Hauptgerüst von allen
GUI-Komponenten, sowie die Implementierung der Mauszeiger und des
GUI-Managers. Beachten Sie, dass Sie zum kompilieren eines Programms mit Andorra 2D
GUI die Komponentensammlung "JVCL" installiert haben müssen, bzw. die benötigte Bibliothek "JvSimpleXML" und alle dazugehörigen Dateien im Suchpfad von Delphi eingetragen sind (unter Delphi in Tools->Optionen->Bibliothek -
Win32).
Außerdem muss die
Unit "AdComponents" eingebunden werden, falls Sie auf die mitgelieferten Komponenten zurückgreifen. Mit dem Einbinden der Klasse werden die entsprechenden Komponenten im
GUI-System registriert. Vergisst man das Einbinden, so kommt es beim Laden der
GUI zu einer entsprechenden Fehlermeldung, da die angegebenen Komponenten nicht registriert sind und daher nicht gefunden werden können.
Wir benötigen zunächst eine Instanz der Klasse "TAdGUI" - diese kümmert sich automatisch um Laden, Speichern, Skins und Mauszeiger.
Delphi-Quellcode:
AdGUI := TAdGUI.Create(AdDraw);
//Erzeugen der Klasse
AdGUI.Skin.LoadFromFile('
sunna.axs');
//Laden des Skins
AdGUI.Cursors.LoadFromFile('
cursors.xml');
//Laden der Cursor
AdGUI.LoadFromFile('
gui.axg');
//Laden der GUI
Natürlich muss "AdGUI" am Ende wieder schön freigegeben werden.
Eigentlich sollten diese Schritte reichen um die
GUI anzuzeigen. Die Betonung liegt dabei jedoch auf dem letzten Wort - man kann die Maus so fest drücken wie man möchte, es tut sich nichts. Woher auch? Schließlich müssen Maus- und Tastaturereignisse erst einmal an das
GUI-System weitergeleitet werden. Dazu gibt es zwei Möglichkeiten. Zunächst erstmal die einfache, die auch in den meisten Fällen zunächst genügen sollte.
Wir bedienen uns der Klasse "TAdGUIConnector" aus der
Unit "AdGUIConnector". Dazu sind die folgenden Schritte nötig:
Delphi-Quellcode:
AdConnector := TAdGUIConnector.Create(AdGUI);
AdConnector.ConnectEventHandlers(self);
Und auch der
GUI-Konnector sollte beim Beenden des Programms wieder schön freigegeben werden.
Allerdings hat der
GUI-Konnector (noch) ein paar Mankos: Man kann die Events nur mit einer Komponente der Klasse "TForm" verbinden - liegt das AdDraw zum Beispiel auf einem Panel, so müssen die Events manuell weitergegeben werden.
Diese Methode ist jedoch nicht weiter schlimm und bringt sogar noch einen weiteren Vorteil mit sich: Man stelle sich ein Aufbauspiel vor, in dem sich frei verschiebbare Fenster auf dem Bildschirm befinden. Woher soll das Spiel nun wissen, ob wir auf das Fenster, oder auf das Spielfeld geklickt haben? Bei der manuellen Verknüpfung ist das kein Problem:
Delphi-Quellcode:
procedure Form1Click(Sender:TObject)
var
p:TPoint;
begin
GetCursorPos(p); //Aktuelle Mauszeigerkoordinaten auslesen
p := ScreenToClient(p); //In Koordinaten relativ zum Formular umrechnen
if not AdGUI.Click(p.X, p.Y) then //Ereignisbehandlung ausführen
begin
//Es wurde auf das Spielfeld geklickt
end;
end;
Es wird hierbei einfach die "Click"-Methode des
GUI-Systems aufgerufen, die rekursiv die Clickmethoden jedes weiteren Elements aufruft. Wird festgestellt, dass der Klick tatsächlich auf einem Steuerelement gelandet ist, so gibt die "Click"-Methode den Wert "true" zurück.
Analog funktioniert das auch mit jedem weiteren Eventhandler.
Auf Steuerelemente zugreifen
Nun wäre es noch äußerst Praktisch, wenn wir auf die im Editor erstellten Elemente in unserem Programm irgendwie zugreifen könnten. Im Editor bekommen die Elemente unter der Eigenschaft "Name" einen Namen zugewiesen - wie in Delphi. Die Methode "FindComponent" von TAdGUI liefert uns unter Angabe des entsprechenden Namens das gesuchte Element zurück. Um auf komponentenspezifische Eigenschaften zuzugreifen, müssen wir das Ergebnis nur noch in die entsprechende Komponentenklasse "casten":
TAdButton(AdGUI.FindComponent('AdButton1')).Caption := 'Hallo!';
Steuerelementevents
Unser
GUI-System ist noch ein wenig leblos - auf Ereignisse wie Klicks reagieren wir noch überhaupt gar nicht.
Dazu können wir einfach Prozeduren mit Ereignissen wie "OnClick" verbinden. Wir müssen dazu eine Prozedur erstellen, die genau die gleichen Parameter wie die Ereignisprozedur besitzt. Welche genau das sind, erfährt man in der Codevervollständigung. Beachten Sie, das die deklarierte Prozedur Bestandteil einer Klasse sein muss. Beispiel:
Delphi-Quellcode:
type
TForm1 =
class(TForm)
[...]
private
procedure AdButtonClick(Sender:TObject);
public
[...]
end;
[...]
procedure TForm1.AdButtonClick(Sender:TObject);
begin
TAdButton(AdGUI.FindComponent('
AdButton1')).Caption := '
Du hast mich geklickt!';
end;
procedure TForm1.FormCreate(Sender:TObject);
begin
//Andorra 2D initialisieren
[...]
//Gui Laden
[...]
//Ereignisse zuweisen
TAdButton(AdGUI.FindComponent('
AdButton1')).OnClick := AdButtonClick;
end;
Übrigens funktioniert dies innerhalb der
VCL genauso.
Eigene Komponenten
Um eigene Komponenten zu erstellen, leiten Sie eine Klasse von "TAdComponent" ab, und registrieren Sie diese im "initialization" Abschnitt der
Unit. Wie genau dies Funktioniert, schauen Sie sich gemäß dem Motto "Code sagt mehr als 1000 Worte" am besten in der
Unit "AdComponents" ab. Um Ihre Eigenentwicklungen im Editor zu verwenden, müssen Sie die entsprechende Klasse auch dort einbinden.
Code um eine geladene GUI zu erweitern
Der Aufruf von "LoadFromFile" ersetzt normalerweise die komplette
GUI - mit foldendem Code kann dies umgangen werden. Beachten Sie, dass Sie zusätzlich die
Unit "JvSimpleXML" einbinden müssen.
Delphi-Quellcode:
procedure ExpandGUI(afile:
string);
var
elems:TJvSimpleXMLElems;
xml:TJvSimpleXML;
j:integer;
cref:TPersistentClass;
function SearchFirst(elem:TJvSimpleXMLElem):TJvSimpleXMLElems;
var
i:integer;
begin
result :=
nil;
for i := 0
to elem.Items.Count - 1
do
begin
if elem.Items[i].
Name <> '
TAdGUI'
then
begin
result := elem.Items;
exit;
end
else
begin
result := SearchFirst(elem.Items[i]);
if result <>
nil then
begin
exit;
end;
end;
end;
end;
begin
xml := TJvSimpleXML.Create(
nil);
xml.LoadFromFile(afile);
elems := SearchFirst(
xml.Root);
if elems <>
nil then
begin
for j := 0
to elems.Count - 1
do
begin
cref := GetClass(elems.Item[j].
Name);
if cref <>
nil then
begin
with TAdComponent(TAdComponentClass(cref).Create(AdGUI))
do
begin
LoadFromXML(elems.Item[j]);
end;
end;
end;
end;
xml.Free;
end;
Fazit
Diese Informationen sollten Ihnen helfen sich mit dem
GUI-System außeinander zu setzen. Am wichtigsten ist es, sich die Eigenschaften der Komponenten zu betrachten. Scheuen Sie auch nicht davor in die Implementierung einer Komponente zu blicken - dann lösen sich aufkommende Fragen meist von selbst. In Delphi aber auch in Lazarus ist dies schließlich ganz einfach: Wenn Sie mit gedrückter STRG-Taste auf einen Bezeichner klicken, so springen sie automatisch zu dessen Deklaration.
Copyright und Lizenz
(c) by Andreas Stöckel November 2007
Der Inhalt dieses Tutorials steht unter der
GNU Lizenz für freie Dokumentation
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein