Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Code:
r:=GetRenderer();// Render Komponente suchen oder Default Renderer erstellen und cachen
Meine Frage wäre: wer entscheidet, welcher Renderer erstellt wird? Ist das von der WidgetKlasse abhängig? Oder gibt er einen String mit? Von mir aus auch ein Enum, wie Sidorion vorgeschlagen hat. Aber irgendwas muss die Funktion GetRenderer ja mitkriegen.
EDIT: OK, hast ja recht, Lars. ist völlig egal, was man ihm mitgibt.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ich halte im Augenblick bei Variante Nr.1. Mein derzeitiger "Renderer" ist einfach ein Teil des GraphTools (=Canvas) und daher statisch, aber erweiterbar. Wenn man eine neue Zeichenprozedur schreibt, erweitert man ihn. Das hat den Nachteil, dass jede Zeichenprozedur eine Frameprozedur braucht. Ich mache das im Augenblick so, dass meine Zeichenprozedur einfach zwei interne Zeichenprozeduren beinhaltet, eine "DrawArea" und eine "DrawFrame", wobei man sich entscheiden kann, ob man nur die Area oder nur den Frame zeichnet oder beides. Aufgerufen wird diese Zeichenmethode über einen Methodenzeiger, weil dieser leicht durch einen anderen ersetzbar ist (Stichwort Themes).
Es liegt nicht am Funktionieren, denn funktionieren müssen alle vorgeschlagenen Varianten. Für mich stellt sich die Frage, welche dieser Implementierungsarten am deutlichsten ist. Ich hätte gern, dass man hinschaut und sagt: "Na klar so geht das" und dass man dabei mit einer großen Wahrscheinlichkeit richtig liegt. Von diesem Blickwinkel gesehen ist die Renderer-Methode klar im Vorteil.
EDIT:
Das bedeutet: Ich tendiere eindeutig zu Deiner Variante Nr.3. Jedes Widget sollte seinen individuellen Renderer bekommen:
im Konstruktor den Klassen-Default-Renderer (kann ja auch ein Property sein, oder?). Themes kann ihm einen neuen zuweisen, und zwar genauso wie bei allen anderen Eigenschaften: aus einer Liste des GraphTool (so wie ichs derzeit mache), weil der Renderer jetzt - so wie alle anderen Visuellen Eigenschaften - ein Objekt ist. Damit mutiert mein Methodenzeiger einfach zu einem Objekt; die Vorgangweise bleibt dieselbe, wie ich sie jetzt im Augenblick habe. Und die Probleme bleiben auch dieselben: wenn mein Widget grundsätzlich alle Renderer bedienen können muss, müssen die Zeichenmethoden des Renderer genormt sein, es geht nicht, dass die Zeichenmethoden verschiedene Parameter entgegennehmen. Wozu brauch ich dann eigentlich ein Objekt? Ich habe keine Vorteile mehr aus der Vererbung.
Ja klar, wenn Du ein TElllipseButton aus dem TButton ableitest, OK. In diesem Fall können die abgleiteten Renderer wirklich verschiedene Zeichenmethoden haben. Das geht aber nicht. Ein TButton muss ein Allrounder sein, der mit allen Zeichenmethoden zurande kommt.
Wenn man für jedes Objekt einen eigenen Renderer hat, hat man nicht viel gewonnen. Da könnte man auch direkt von der Komponente ableiten und die Zeichenmethode überschreiben. Die Idee ist ja den Code für gemeinsame Primitive auszulagern um ihn einfach austauschen zu können(=Theme). Daher muss diese Schnittstelle genormt sein. Die Schwierigkeit ist herauszufinden welche Elemente zu einem Theme gehören.
mögliche Elemente wären:
Rahmen: versenkt, erhöht, Fensterrahmen
Button-Hintergrund: gedrückt, oben, aktiviert,
einfacher Text
Bild
Pfeil
Checkbox-Kästchen: ausgewählt, normal
....
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo Lars,
ich habe gestern und heute drüber nachgedacht, was das beste wäre. Ich habs mir nicht leicht gemacht und habe versucht, mir die weitere Entwicklung vorzustellen, mit allen drei mir jetzt vorliegenden Varianten. Zuletzt bin ich zu forlgendem Schluss gekommen (ich vergleiche die Enum-Methode, meine Methoden-Zeiger-Methode und Deine Renderer-Methode):
Ich halte Deine Renderer-Methode für die Beste, weil
1) sie ist genauso funktionell wie die anderen beiden
2) sie ist genauso schnell wie die anderen beiden
3) sie hat den Vorteil der Kapselung aller notwendigen Routinen, die man für das Zeichnen eines Widgets braucht und ist daher m.E. besser gerüstet für zukünftigen Ausbau und ist trotzdem übersichtlich und verständlich
Daher werde ich die Renderer-Methode nehmen.
Danke
Traude
Was ich jetzt hierbei nicht verstehe ist folgendes:
Ein Knopf braucht Rahmen, Knopffläche (in verschiedenen Statusen), Text; Ein Edit braucht Rahmen, Eingabefeld, Text, ein Panel braucht Rahmen und Hintergrung (also auch wieder ne Fläche).
d.h.: Die ZeichenProzedur vom Knopf sieht so aus:
Code:
If Pressed then Renderer.TextureRect(PressedTexID, left, top, width, height)
ElseIf MouseOver then Renderer.TextureRect(MouseOverTexID, left, top, width, height)
usw.
Meiner Meinung nach sollte der Renderer also eine Menge von Zeichenroutinen bereitstellen, die das Widget rufen kann. Welche das sind, hängt von der Widgetklasse ab. wenn man also einen sechseckigen Knopf haben will, beerbt man einfach das Knopf-Widget und ruft statt TextureRect TextureHexagon. Bzw könnte man den 'Zeichenstil' auch mitgeben ala TextureShape(Left,Top,Width,Height,dsHex [oder dsRectangle, dsRoundRect]). Ich denke, Ihr geht zu speziell vor, d.h. die Zeichenroutine soll das ganze Wiget zeichnen.
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Ich bin gerade dabei, den Code auf den Renderer umzuschreiben, es funktioniert schon alles wieder, nur bei der Ellipse hakt es noch ein wenig. Die Schrift habe ich nicht im Renderer drin, weil bisher meine Drawing Procedure auch keine hatte. Schrift ist ja auch bloss ein Zeichenmittel, das man sich - wie den Renderer - aus einem "Pennal" holen und benutzen kann: siehe unten Button-Code. Ob ich die Schrift in den Renderer einbaue, weiß ich noch nicht.
Vermutlich fehlt noch eine Menge, was mir erst auffallen wird, wenn ich jetzt die Widgets mache. Das muss ich dann "On The Fly" nachholen.
Zitat:
Ich denke, Ihr geht zu speziell vor, d.h. die Zeichenroutine soll das ganze Wiget zeichnen.
Ich zeichne schon das ganze Widget. Du brauchst für einen sechseckigen Knopf keine abgeleitete Klasse, es reicht der TButton, dem Du einen Hexagon-Renderer gibst:
Der Button zeichnet gar nicht mehr, das macht seine Vorfahrklasse mit der Prozedur "TRenderer.Draw". Der Button stellt seine Zeichenmittel bereit, die man ihm per Theme oder auch individuell geben kann: Farbe/Renderer/Textur/Schrift, DAMIT sein Vorfahr damit zeichnen kann. Ansonsten kümmert sich der TButton nur um sein "Verhalten".
Unten der SourceCode für den (funktionierenden) TestButton (wie man an der Zeile mit der "//&&&&&"-Markierung sieht, habe ich noch Schwierigkeiten mit der Positionierung meiner FreeType-Schrift):
Code:
Procedure TGUIButton.Paint;
Begin
// HOVER berücksichtigen
If fRoot.HoveredItem <> Self
Then fFrameState:= fsFlat;
// Farbe einstellen
If fFrameState = fsRaised
Then FGColor.Gradient:=0.7
Else FGColor.Gradient:=0.5;
Inherited Paint;
// Schrift zentrieren und schreiben
fPosX:= Left +(Width Div2)-(Font.TextWidth(fCaption)Div2);
If fPosX < 0Then fPosX:=0;
fPosY:= Top +(Height Div2)-(Font.TextHeight(fCaption)Div2)-10;//&&&&&
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Mich hat vor kurzem jemand gefragt, ob ich ein 3D-Widget (mit Triangle-Listen) machen würde. Ich sagte Ihm, dass ich jetzt endlich die 2D-Widgets bauen möchte und dieses Feature überhaupt nicht gefragt ist.
Allerdings hat dieser Jemand genau meinen wunden Punkt getroffen. Denn ich mache immer noch nur meinen Bounding-Box-Hittest mit den Punkten Links/Oben/Rechts/Unten. Für die ganz normalen Anwendungen ist das genug. Aber schon bei kreisförmigen Widgets seh ich mit diesem Hittest ziemlich alt aus.
Der neue Renderer kann runde Widgets zeichnen. Was macht er da? Er plottet Punkte auf einer Kreislinie und verbindet diese zu einem Polygon. Die Texturkoordinaten erzeugt er gleich mit. Er errechnet im Augenblick diese Punkte/ Texturkoordinaten bei jedem Rendervorgang neu.
Er könnte aber genauso die Punkte und Texturkoordinaten nur einmal rechnen, das ganze selbständig in Dreiecke zerlegen und die Daten dann in einer Punkte-Liste ablegen (braucht allerdings ein bissl Speicherplatz). Mit dieser Punkteliste könnte das Widget einen GESTALTGENAUEN Hittest machen.
Ob auch Animationen damit möglich sind, weiß ich noch nicht. Ist nur mal so eine nicht ausgegorene Idee.
>>unschuldig guck<<
Das ist ja eine prima Idee .. kannste das gleich mitmachen?
Nee Polygenau reicht völlig, Animationen müssen nicht sein. das muss dann der User durch Manipulation der Punktelliste oder sonstiger Eigenschaften am Widget selber machen.
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ich frag ja nur, weil man mir anfangs (vor vielen, vielen Seiten) unmissverständlich zu verstehen gegeben hat, das so etwas nicht gewünscht ist. Nur jetzt wäre es einfach ein Nebeneffekt bei der Implementierung eines besseren Hittest. Ist natürlich eine Ausrede von mir. Ich wollte das immer schon dabei haben.
Ich find ja wabbelnde Knöppe auch geil, also wenns eh abfällt, dann leg los
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2621 Wohnort: Berlin
Programmiersprache: Go, C/C++
Naja das ich der "jemand" war kannst ruhig sagen .
Ich hab das Polygonbasierte Prinzip schon ziemlich weit implementiert und werde wohl in kürze die widgets umstellen. So kommen allerdings auch neue funktionen hinzu. Neben dem AddVertex für die Liste gibt es vorgefertigte Befehle z.B. addRoundShadedBox wo man dann die anzahl an punkten für die rundung der ecken mit angeben kann.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Mitglieder in diesem Forum: 0 Mitglieder und 31 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.