![]() |
Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Seit einiger Zeit habe ich mit den Delphi Styles einwenig experimentiert. Da ich eine Menge eigener (visueller) Komponenten habe stellt sich mir aber nun die Frage, wie man am besten deren Style integriert, sodass sie bei einem Stylewechsel passend angezeigt werden.
Für ein paar ganz einfach Komponenten reicht es natürlich im Paint() die StyleServices zu verwenden und eventuell auch System oder Stylefarben für eigene Zusätze zu "missbrauchen". Mitunter gibt es aber komplexere Komponenten, die mehrere zum Style passende Elemente benötigen würden (in der Regel eigene Farben wie zum Beispiel bei einer "Log"-Komponente die für Fehler, Warnungen und normalen Text unterschiedliche Farben benötigt - und das eben abhängig vom durch einen Style gegebenen Hintergrund). Hin und wieder wären aber auch ein paar Grafiken von Vorteil die auch, abhängig vom Style, mal heller mal dunkler daherkommen sollten. Irgend etwas zu den original Styles hinzuzufügen ist ja wohl verboten und auch Kopien davon, dafür zu verwenden erscheint mir nicht gerade vernünftig. Man könnte natürlich für jede Komponente die entsprechenden Ressourcen für alle momentan bekannten Styles speichern und bei einem Stylewechsel nachsehen ob Einstellungen dafür vorhanden sind (über den Stylenamen?) und diese dann verwenden. Ist aber mühsam und bei einer Lib mit 50+ Komponenten ganz schön aufwendig und dann auch über die ganze Lib. verstreut! Schön wäre es etwa, wenn ich für alle Komponenten ein gemeinsames Style-File haben könnte indem nur meine Einstellungen enthalten sind (scheitert schon mal daran, dass im Bitmap-Stil-Designer ein "Neu"es Projekt komplett mit einer vollen Konfiguration bestückt ist und leider Löschen auch verboten ist). Theoretisch könnte ich dann für jeden Delphi Style eine eigene .vsf haben und diese müsste mit ausgeliefert werden (ob als eigenständige Datei oder auch als Ressource) und dann müsste es auch noch eine Methode geben, die meine Zusätze mit denen der dazugehörenden Styles verbindet.... Letzteres wäre dann auch noch ein zweites Mal von Vorteil, weil auch die eigentliche Applikation noch styleabhängige Komponenten mitbringen kann (z.B.: einen umfangreichen Satz an Icons die zumindestens für "helle" und "dunkle" Styles andere Farben haben müssen)... Also eine Menge Fragen, ich hoffe, dass es - wie immer - ein paar Spezialisten gibt, die sich damit auskennen... |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Wenn du in deinen Komponenten viel selber auf den Canvas zeichnest, bieten sich die Methoden von StyleServices an. Beispielsweise GetSystemColor und GetStyleColor. Welche Farben das für die einzelnen Styles sind, kann man sich im Bitmap Style Designer unter "Colors" und "SysColors" anschauen. Eine weitere Möglichkeit wäre das Schreiben eigener StyleHooks für deine Komponenten. Somit wäre zumindest das Zeichen im Styling-Fall von den bisherigen Code entkoppelt. Das VCL Styles Project ist dir ein Begriff? ![]() |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Ja kenn ich, hab auch selber ein paar fixes für Delphi XE5 an den StyleHooks gemacht... ist aber ein Beispiel dafür, wie man es eben nicht machen sollte die eigenen Erweiterungen in den Originalstyle zu integrieren ist - aus meiner Sicht - ein "no go".
Vielleicht waren meine Fragen aber wirklich nicht klar genug definiert. Die Hauptfrage ergibt sich aber aus dem Titel des Threads: 1. Korrekter Umgang mit Delphi Styles und eigenen Komponenten? 1.1. Eigene Farben für jeden Stil definieren (wo am besten)? 1.2. Eigene Graphiken für jeden Stil definieren (wo/wie)? 2. Korrektes Management für die einzelnen Zusätze 2.1. Wo hin mit den eigenen Definitionen (siehe 1.1, 1.2)? 2.2. Wie linken mit den bestehenden Styles (so dass, die Umschaltung eines Styles auch die eigenen Komponenten betrifft)? Alles andere sind Gedanken die ich mir zu diesem Thema gemacht habe und sollte nur zeigen in welche Richtungen meine Überlegungen bisher gegangen sind. |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Ich habe die VCL.Styles aufgegeben. Was nützt es, wenn die 3 Standard-Komponenten unterstützt werden, aber die 20 anderen Fremdkomponenten nicht. Ich hab keine Zeit mich darum auch noch zu kümmern. Das ganze Konzept des skinning taugt nicht in Delphi, weil es nicht adaptiv ist. Ausserdem sollte das immer die Aufgabe des nativen Betriebssystems sein.
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Zitat:
Zumindestens von Steema weis ich, dass mit dem nächsten Release Style Support kommen wird (habe aber keine Ahnung wann konkret <Kristallkugel> wohl spätestens irgendwann im Herbst </Kristallkugel> und wie das Ganze dann aussehen wird). Zitat:
Zitat:
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Von XE5 auf XE6 wurde die
![]() (Soll nur ein Hinweis sein, deine eigentlichen Fragen beantwortet das nicht) |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe mich in meiner eigenen Anwendung auf einen einzigen selbst erstellten Style konzentriert.
Jeden Style abdecken zu wollen ist eine Mammutaufgabe. Fraglich auch, ob das sinnvoll ist. Ich würde den Anwender die Wahl lassen zwischen den normalen Windows-Style und einen anderen. Dementsprechend muss man ggf. alles doppelt haben: Imagelisten, Image-Ressourcen usw. und zur Laufzeit beim Programmstart austauschen. Die Farben müssen dann entsprechend aus den Style extrahiert werden (GetSystemColor/GetStyleColor). Hier mal so ein Minimalbeispiel:
Delphi-Quellcode:
unit StylesTestFrm;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, System.Generics.Collections, Vcl.Themes, Vcl.ImgList; type TLineState = (Start, Move, Stop); TPainter = class strict private FIsLineStarted : Boolean; FCanvas : TCanvas; FImageIndex : Integer; FImageList : TImageList; FPoints : TList<TPoint>; public procedure Clear; function PaintLine(LineState : TLineState; X, Y : Integer) : Boolean; procedure Paint; constructor Create(ACanvas : TCanvas; AImageList : TImageList); destructor Destroy; override; property IsLineStarted : Boolean read FIsLineStarted write FIsLineStarted; end; TForm2 = class(TForm) PaintBox1 : TPaintBox; ilSystem : TImageList; ilStyle : TImageList; procedure FormCreate(Sender : TObject); procedure PaintBox1MouseDown(Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer); procedure PaintBox1MouseMove(Sender : TObject; Shift : TShiftState; X, Y : Integer); procedure PaintBox1Paint(Sender : TObject); procedure PaintBox1MouseUp(Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer); procedure FormDestroy(Sender: TObject); private FPainter : TPainter; public end; var Form2 : TForm2; implementation uses System.Math; {$R *.dfm} procedure TForm2.FormCreate(Sender : TObject); var LCurrentImageList : TImageList; begin LCurrentImageList := ilStyle; if StyleServices.IsSystemStyle then begin LCurrentImageList := ilSystem; end; FPainter := TPainter.Create(PaintBox1.Canvas, LCurrentImageList); end; procedure TForm2.FormDestroy(Sender: TObject); begin FPainter.Free; end; procedure TForm2.PaintBox1MouseDown(Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer); begin case Button of TMouseButton.mbLeft : begin if FPainter.PaintLine(TLineState.Start, X, Y) then PaintBox1.Repaint; end; end; end; procedure TForm2.PaintBox1MouseMove(Sender : TObject; Shift : TShiftState; X, Y : Integer); begin if FPainter.PaintLine(TLineState.Move, X, Y) then PaintBox1.Repaint; end; procedure TForm2.PaintBox1MouseUp(Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer); begin case Button of TMouseButton.mbLeft : begin if FPainter.PaintLine(TLineState.Stop, X, Y) then PaintBox1.Repaint; end; TMouseButton.mbRight : begin FPainter.Clear; PaintBox1.Repaint; end; end; end; procedure TForm2.PaintBox1Paint(Sender : TObject); begin if Assigned(FPainter) then begin FPainter.Paint; end; end; procedure TPainter.Clear; begin FCanvas.FillRect(FCanvas.ClipRect); FPoints.Clear; FImageIndex := 0; end; constructor TPainter.Create(ACanvas : TCanvas; AImageList : TImageList); begin FCanvas := ACanvas; FImageList := AImageList; FPoints := TList<TPoint>.Create; FCanvas.Pen.Width := 5; FCanvas.Pen.Color := StyleServices.GetSystemColor(clHighlight); FCanvas.Brush.Color := StyleServices.GetSystemColor(clBackground); end; destructor TPainter.Destroy; begin FPoints.Free; inherited; end; procedure TPainter.Paint; var LPoints : TArray<TPoint>; LLastPosition : TPoint; begin LPoints := FPoints.ToArray; FCanvas.Polyline(LPoints); if InRange(FImageIndex, 0, FImageList.Count - 1) then begin Inc(FImageIndex) end else begin FImageIndex := 0; end; if FPoints.Count > 0 then begin LLastPosition := FPoints.Last; FImageList.Draw(FCanvas, LLastPosition.X + 3, LLastPosition.Y + 3, FImageIndex); end; end; function TPainter.PaintLine(LineState : TLineState; X, Y : Integer) : Boolean; var LPosition : TPoint; begin LPosition := TPoint.Create(X, Y); case LineState of Start : begin FPoints.Add(LPosition); IsLineStarted := True; end; Move : begin if IsLineStarted then begin if LPosition <> FPoints.Last then begin FPoints.Add(LPosition); end; end; end; Stop : begin if IsLineStarted then begin FPoints.Clear; IsLineStarted := False; end; end; end; Result := IsLineStarted; end; end. |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Für eigene Applikationen mache ich das in geeignetem Rahmen auch so ähnlich und da kann man sich sicher auch auf ein paar wenige Styles beschränken.
Mir geht es aber eher um (m)eine Komponenten Library die ja dann für anderen Entwickler und deren Projekte verwendet werden und damit wird es schon schwieriger einen Style vorzuschreiben! |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Aha, eine wichtige Info!
Ich denke mal, du zeichnest irgendwas (Charts, Diagramme) und bist darauf angewiesen, dass bestimmte Farb- und Helligkeitsunterschiede vorhanden sind. Auf einen Panel, was früher Windows grau war und nun durch Styling dunkelgrün, kann man wahrscheinlich schlecht hellgrüne Linien einzeichnen. Vielleicht suchst du einfach nur nach einer Lösung, um eine bestehende Farbe zu analysieren (Einzelne RGB-Komponenten, Helligkeit, Sättigung)?!? So a la: "Hier ist eine dunkle bzw. helle Hintergrundfarbe, bitte gib mir ein passenden Canvas.Pen.Color". |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Liste der Anhänge anzeigen (Anzahl: 1)
Posting #1 und #3 fassen das eigentl. recht gut zusammen und für einfache Sachen kann man sich ja Farben vom Style "ausborgen" aber mir geht es hauptsächlich darum wie man zusatzinfos zu bestehenden Styles definieren könnte und diese dann mit den bestehenden "verlinkt" damit für den Endanwender alles wie aus einem Guss aus sieht.
Farben zu analysieren ist kein Thema aber das schöne an einem Style ist ja gerade, dass alle Farben aufeinander abgestimmt sind (hoffentlich :twisted:) und dann nur noch verwendet werden müssen. Als konkretes Beispiel könnte man sich eine kleine Komponete vorstellen die einen Graphen - im Sekundentakt - nach rechts oder links scrollt (siehe angehängtes Bild, schnell mit Gimp erstellt - nichts reales). Da gibts jetzt einen Rand, ein paar Linien ein Hintergrundraster, eine Cursorline und eventuell ein Image das als Indikator je nach zugrundeliegendem Signal anders aussehen könnte. Für so eine Komponente wären nun also 5-6 Farben für alle Elemente nötig plus - zb. 3 Images (niedrig,mittel, hoch). Das Ganze nun für jeden der (unter XE5) vorhandenen 27 Styles.... |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Man könnte sich jetzt den Aufwand machen und anhand der Style-Farben sich irgendwas passendes für den Graphen extrahieren.
Aber ich denke, dass ist der falsche Weg! :warn: Derartige Eigenschaften gehören published, damit der Anwender selber entscheiden kann, welche Farben er einsetzt. Bedenke, dass es neben den mitgelieferten Styles noch selbst erstellte Styles gibt. Für unsere Anwendung bspw. habe ich mir vom Style 'Carbon' eine Kopie erstellt und die weiter verfeinert (clHighlight ist z.B. orange anstatt Pastellfarbenblau). Von daher ist es unmöglich sich irgendeine Form von Mapping-Tabelle zu erstellen. |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Ich habe nicht die 'Carbon.vsf' an sich bearbeitet! Sondern kopiert und umbenannt a la 'MyStyle.vsf' und dort dann fröhlich geändert. Die VSF-Datei wird vom Installer neben die EXE gelegt und dann dynamisch beim Programmstart geladen. Sehe nicht, dass ich mich damit auf irgendeine spezielle Delphi-Version festlege?? |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Sobald Emba etwas an seinen Styles files etwas ändert (wie etwa zwischen XE5 und XE6) hast du ein inkomptiebles style-file.
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Was wurde denn da geändert?
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Sie haben das VCL Styles - Projekt (siehe Posting #2) zugekauft und unterstützen damit z.B. geskinnte Menüs usw. (kennst du ja #2 ist ja von dir)..
Damit befinden sich aber jetzt auch neue Elemente im Style die vielleicht gerade von deinen eigenen Erweiterungen überschrieben wurden (die älteren png's in den Styles hatten rechts-unten ein bischen Freiraum, der ist jetzt weg). Grundsätzlich ist es aber egal wohin auch immer du deine Bitmaps packst, Emba kann dort in der nächsten Erweiterung wieder eigene Sachen haben. Prinzipiell ist das auch ein gutes Beispiel dafür, dass das Ändern eines Originalstyles (und ich meine damit definitiv kopieren + ändern) keine gute Idee ist! |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Da ist aber kein Unterschied zu einem konmplett selber entwickelten Skin.
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Dann schon wenn du etwa Komponenten von drei verschiedenen Herstellern hast und die auf die Idee kämen alle "ihren Eigenen" Style mitzuliefern ... dann kannst du nämlich schlechtestenfalls nur mehr von einem Drittel deines Programms das aussehen bestimmen... |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Nochmals: Meine VSF-Datei wird nicht über Project Options -> Application -> Appearance in das Programm eingebunden. Die VSF-Datei wird vom Installer in das Programm-Verzeichnis gelegt. Das Programm lädt diesen Style bei Vorhandensein. Im Style selber sind die Elemente (die Objects im Bitmap Style Designer) und deren Aussehen (Images -> style.png) fix und fertig einkompiliert. -> Die VSF-Datei selber ist wie eine DLL. Da können die bei Embarcadero in den zukünftigen XE-Versionen ja fröhlich weitere Objects in ihre mitgelieferten Styles einfügen und das Style.png ergänzen, dass ist von meinen eigenen Style ganz unabhängig! |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Es kann in der gesamten Applikation nur ein Style geladen werden, oder habe ich irgendwas übersehen? :?: |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
:D ... ja genau das ist das problem (oder eben nur mangelndes know how) ...
|
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Warum ist das ein Problem?
Es wäre äußerst ungünstig, wenn mehrere Styles für verschiedene Komponenten geladen werden könnten. |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Das will ja auch keiner. Vieleicht versuche ich es noch mal zu erklären, ich glaube nämlich, dass noch nicht ganz klar ist, worauf ich hinaus will. 1. Hersteller A hat eine Komponentenbibliothek und liefert für jeden Delphi Style einen Zusatz (etwa in Form von "Styleerweiterungsdateien: zB.: Amakrits_A.vsf, AmethystKamri_A.vsf, ... , SmokeyQuartzKamri_A.vsf, TurquoiseGray_A.vsf). Diese Styledateien enthalten NUR Styledaten die für die Bibliothek relevant sind aber KEINE Allgemeinen Daten wie für TForm usw.. 2. Hersteller B hat auch eine Komponentenbibliothek und liefert dafür auch entsprechende Dateine (Amakrits_B.vsf, AmethystKamri_B.vsf, ... 3. Wir kommen zu Hersteller C der hat dann: Amakrits_C.vsf, AmethystKamri_C.vsf, ... 4. Du selber hast auch noch eine tolle Komponente und machst dir auch entsprechende Dateien (also Amakrits_Z.vsf, AmethystKamri_Z.vsf, ... 5. Bei der Installation der Komponentenbibliotheken der drei Hersteller bei dir am PC registrieren sich nun die Erweiterungen jedes Herstellers ZUM dazugehörigen Delphistyle (also Amakrits_A, Amakrits_B, Amakrits_C und Amakrits_Z bei Amakrits.vsf; AmethystKamri_A, AmethystKamri_B, AmethystKamri_C, AmethystKamri_Z bei AmethystKamri.vsf usw. 6. Jetzt kannst du als Programmierer deine Applikation erstellen und ein Fenster designen in dem du sowohl ein paar Delphi Komponenten als auch welche von Hersteller A von Hersteller B von Hersteller C und natürlich auch deine eigene verwendest. Du wählst dir 2-3 Styles aus zwischen denen dein Anwender wählen kann und erstellst die Applikation. Damit sieht dein Fenster wie aus einem Guss aus, obwohl es visuelle Komponenten von 5 verschiedenen Quellen enthält und wenn der Anwender den Style ändert funktioniert das auch..... ... die Frage ist, gibt es eine Möglichkeit sowas zu bewerkstelligen bzw. wie mit der obigen Situation umgegangen werden muss... |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
Zitat:
Letztendlich basieren die meisten Komponenten auf schon bekannten (Windows-)Komponenten (Panel, Edit, Label) oder heben sich bewusst vom herkömmlichen Stil ab (bspw. ![]() Erstere sollten sich entsprechend der Definitionen im verwendeten Stil verhalten. Letztere sollen sich bewusst abheben bzw. möchte ich als Enwickler immer selber entscheiden können, wie Gradienten, Farben und Texte darin auszusehen haben. Bleiben wir bei deinem abstrakten Beispiel vor einigen Posts mit dem Diagramm/Chart: Auch wenn mein gerade verwendeter Style sehr dunkel ist (z.B. Carbon, Metro Black) möchte ich vielleicht, dass der Diagrammhintergrund weiterhin weiß ist oder ein Gradient ist von beige bis hellblau. Einfach aus Gewohnheit oder besserer Lesbarkeit oder weil es der Auftrag/Pflichtenheft so vorgibt. Die Komponente muss mir also immer die Möglichkeit geben, das Styling selektiv über die published property StyleElements ein- oder auszuschalten. Du hast als Komponentenhersteller gar nicht die Zeit und Möglichkeit für alle RAD Studio eigenen Styles dir irgendwelche speziellen Sachen für jede deiner Komponenten auszudenken. Ganz zu schweigen von den Styles aus der Delphi-Community selbst bzw. vom jeweiligen Anwender. |
AW: Korrekter Umgang mit Delphi Styles und eigenen Komponenten
Zitat:
... Ich gehe sogar so weit zu sagen, dass sowas (ähnliches) Grundvoraussetzung ist, um ein einigermaßen brauchbares System zu erhalten... sonst kann ich ja auch Insellösungen wie AlphaControls oder ähnliches verwenden! Zitat:
Zitat:
Komponenten wie die TMS Gauges sind ja für sich schlüssig und benötigen nur einen zum Stil passenden Hintergrund aber Komponenten wie TChart sind so komplex, das sie eine Menge von Elementen benötigen um einen gutaussehenden Gesamteindruck zu hinterlassen. Zitat:
Zitat:
Und gerade für die größeren, wäre das sogar Pflicht. Ich denke auch, dass das nicht immer so ein großer Aufwand sein muss, in der Regel reichen vielleicht ein paar passende Farben und ein paar Grafiken. Ob die nun irgendwelche Community-Komponenten das auch können (wollen) oder nicht spielt hier keine Rolle, es sollte eigentlich um ein schlüssiges System gehen, dass einen Umgang mit den Styles ermöglicht der über hardcoding im source code hinausgeht (auch wenn Emba. das erst noch umsetzen muss ... wie ich aus dieser Diskussion momentan feststellen muss). |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz