Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi ColorToString auch für Systemfarben (https://www.delphipraxis.net/114764-colortostring-auch-fuer-systemfarben.html)

taaktaak 30. Mai 2008 22:00


ColorToString auch für Systemfarben
 
Moin, Moin.

Ich möchte den Farbwert eines Pixels auch mit dem Namen der "symbolischen Konstante" anzeigen. Die Delphi-Hilfe bietet hierzu ColorToString() und ColorToIdent() an. Ich zitiere:

Zitat:

Mit ColorToString können Sie einen String abrufen, der einem bestimmten TColor-Wert entspricht. Wenn für die Farbe eine symbolische Konstante definiert ist (z.B. clBlack oder clHighlightText)....
Die ersten Testläufe haben mir nun wieder ein paar graue Haare mehr beschert. Beide Funktionen liefern für die "Basisfarben" clBlack bis clWhite wie erwartet die symbolische Konstante zurück. Soll der String aber für eine Systemfarben ermittelt werden, scheitern beide Funktionen und liefern nur einen Hex-Wert zurück.

Also schaue ich mir in "Graphics" die betreffenden Funktionen bzw. Konstanten mal an: Beide Funktionen suchen den übergebenen Wert im const-Array "Colors" - und finden bei Systemfarben offenbar keine Übereinstimmung von übergebenen Farbwert und den im const-Array abgelegten Farbwerten. Die Farbwerte des Arrays sind in der gleichen Unit als Konstanten definiert. Dabei fällt mir auf, dass die "Basisfarben" anders definiert werden als die Systemfarben:

z.B. clBlack = TColor($000000) aber z.B. clBtnFace = TColor(clSystemColor or COLOR_BTNFACE)

Das bringt mich aber noch nicht weiter. Also ermittle ich vielleict erst einmal, welchen Wert ich für einen Pixel der Farbe clBtnFace an die Funktion übergebe und welcher Wert für clBtnFace im Array "Colors" enthalten ist:

TColor(clBtnFace) = 13160660 <- übergebener, zu suchender Wert)
StringToColor('clBtnFace') = -16777201 <- Value im Array "Colors"

Na klar, dann kan nix gefunden werden! Laut Hilfe soll aber bei ColorToString() ein TColor-Wert übergeben werden können und die Bezeichnung auc der Systemfarben ermittelt werden.

Ahhhh, schiete!
Ist die Aussage der Hilfe falsch?
Habe ich ein Brett vor dem Kopf?

Need help :wall:

FAlter 30. Mai 2008 22:08

Re: ColorToString nicht für Systemfarben???
 
Hi,

wie es sich anhört, nimmst du eine "echte" Farbe und willst sie übersetzen. Dabei gibt es folgendes Problem:

Die Systemfarben werden beim Zeichnen durch die "richtigen" Farben ersetzt. Es sind quasi Platzhalter, die je nachdem, welche Farbe du als User eingestellt hast, für eine bestimmte Farbe stehen. Nimmst du nun einen Farbwert aus einem Bild, entspricht dieser auch tatsächlich dem Farbwert und nicht mehr der Systemfarbe, die eventuell genauso aussieht und die es einmal war.

Falls ich deine Verfahrensweise also richtig verstanden habe: Es gibt keine Lösung für dein Problem. Du kannst ColorToString(clBtnFace) eingeben, und erhältst 'clBtnFace'. Malst du aber etwas mit clBtnFace in ein Bild und bestimmst die Farbe im Bild, so ist es irgendein Farbwert. Früher war dies meist gleich clSilver, heute ist es "in", andere Farben zu verwenden. Auf clBtnFace kommst du so leicht nicht mehr zurück.

Mfg
FAlter

himitsu 30. Mai 2008 22:18

Re: ColorToString nicht für Systemfarben???
 
man könnte alle cl...Farbkonstanten in RGB-Werte umwandeln lassen
und dann diese Farben mit der Farbe vergleichen.

nu gibt es obtmal verschiedene cl-Konstanten mit er selben Farbe,
was bedeutet daß nicht immer eine eindeutige Zuordnung möglich wäre.

taaktaak 30. Mai 2008 22:20

Re: ColorToString nicht für Systemfarben???
 
Hmmmmmmmmmmmmm, Grübel....

FAlter - Danke erst einmal für die Antwort....

Wenn ich mir das so überlege.... Windows müsste doch aber eigentlich wissen, welche "tatsächliche" Farbe verwendet wird, wenn ein Programm die Farbe "clBtnFace" verwendet. Man müsste also Windows fragen: Welchen Farbwert verwendest du tatsächlich für "clXXXX". Dann vergessen wir das Array in Graphics, und machen das "zu Fuss" es müssten dann natürlich immer alle symbolischen Konstanten abgefragt werden (?) das dürfte (so überhaupt möglich) nicht besonders schnell sein...

// edit:
@himitsu - wenn ich FAlter aber richtig verstanden habe, dann ist mit Konstanten doch gar nix anzufangen, da die Farben praktisch "dynamisch" sind... Ah, ich geh' jetzt erst mal eine rauchen, muss überlegen...

// edit2:
@himitsu - na, klar! mehrere symbolische Konstanten haben (bzw. können haben) identische Werte - egal wie: eine eindeutige Zuordnung wird nicht möglich sein - du hast Recht!!!

Muetze1 30. Mai 2008 22:29

Re: ColorToString nicht für Systemfarben???
 
1. Die Farbkonstanten welche Farben aus einem Farbschema wiederspiegeln (clBtnFace, etc), können als Konstante nicht mit richtigen Farbwerten definiert werden, da sie auf dem Zielsystem von Windows festgelegt werden, da der Nutzer die Farbschemas frei definieren kann. Somit sind es nur Platzhalter, welcher als Kennzeichnung das 31. Bit gesetzt hat. Dadurch sind diese Konstanten nach einem Typecast auf Integer immer negativ. Die VCL wandelt diese Konstanten u.a. in der Funktion ColorToRGB() um und fragt dann für die jeweilige Konstante Windows nach dem Farbwert.
2. Der Nutzer kann in Windows die einzelnen Farbkonstanten frei festlegen und somit kann der Nutzer auch z.B. rot für den Menühintergrund, einen Button und auch für den Fensterrand definieren. Somit ist es im Endeffekt einfach nur ein RGB Wert, der dahinter liegt. Und von diesem kann man nun nicht mehr eindeutig auf eine solche Farbkonstanten zurückkommen, da es eine 1:n Beziehung ist.
Auch wenn du einen RGB Wert hast, ist die Frage, ob er jemals eine Konstante war oder direkt so genutzt wurde und nicht über eine Konstante ermittelt wurde.

himitsu 30. Mai 2008 22:34

Re: ColorToString nicht für Systemfarben???
 
am Einfachsten du machst dir ein Array mit den clNamen
0 = 'clScrollBar'
1 = 'clBackground'
...

Delphi-Quellcode:
for i := 0 to 31{255} do
  if GetSysColor($ff000000 or i) = C then
    ... { S := MyColorConstArray[i]; }

for i := $ff000000 to $ff00001f{$ff0000ff} do
  if GetSysColor(i) = C then
    ...
(im Notfall ein temporäres Array mit den Farbwerten erstellen, falls man mehrere Farben abfragen und nicht ständig GetSysColor aufrufen will)



Rein theoretisch gibt es nur maximal 256 Systemfarben, wobei aktuell nur die unteren 5 Bit verwendet sind ... also 0 bis 31



Und wie Muetze1 und Co. schon sagten, ist diese Zuordnung dann nur zu diesem Zeitpunkt und auf dem einem System/Benutzer eindeutig.

taaktaak 30. Mai 2008 22:52

Re: ColorToString nicht für Systemfarben???
 
Vielen Dank an alle! :hi:

Habe das grundsätzlich verstanden. Vor diesem Hintergrund macht es dann eigentlich auch keinen besonders großen Sinn, den Namen in einem ColorPicker zu nennen. Nun wird mir auch klar, warum ich die "Farbnamen" noch nicht in einem derartigen Programm gesehen habe...

@himitsu: Ja, es würde sicher ausreichen die Farbzuordnungen beim Programmstart zu bestimmen. Wer während des Programmablaufs die Windows-Farben ändert ist dann selber schuld. Werde den Beispielcode aber erst einmal nicht verwenden, sondern archivieren.

Besser werde ich nun mal am Programm weitermachen, möchte es ja hier bald vorstellen!

taaktaak 30. Mai 2008 23:09

Re: ColorToString nicht für Systemfarben???
 
Ahhh, bevor ich jetzt endlich weitermache, doch noch eine dem Thema folgende Frage:

In Graphics hatte ich ja folgendes gefunden:

clBtnFace = TColor(clSystemColor or COLOR_BTNFACE)

Wenn ich den "Weg " jetzt noch weiter zurück verfolge, dann finde ich die Deklaration der Konstanten COLOR_BTNFACE. Dort steht dann

{$EXTERNALSYM COLOR_BTNFACE}
COLOR_BTNFACE = 15;

Leider spinnt meine Delphi7 Hilfe, wenn ich auf $EXTERNALSYM positioniere und F1 drücke. Was bedeutet das? So laienhaft betrachtet, klingt das nach: "Hole einen Wert von ausserhalb(also von Windows)" - würde das (so ich richtig geraten habe) aber nicht bedeuten, dass im Array "Colors" doch die aktuell in Windows gültigen Farbwerte stehen?

himitsu 30. Mai 2008 23:17

Re: ColorToString nicht für Systemfarben???
 
nee neee, die Konstante (im Beispiel 15) wird nicht verändert/umgewandelt.


Zitat:

Zitat von OH
The EXTERNALSYM directive prevents the specified Delphi symbol from appearing in header files generated for C++. If an overloaded routine is specified, all versions of the routine are excluded from the header file.


taaktaak 30. Mai 2008 23:43

Re: ColorToString nicht für Systemfarben???
 
hihihi,

...prevents...appearing...

falsch geraten :oops: Gute Nacht!

taaktaak 31. Mai 2008 21:19

Re: ColorToString nicht für Systemfarben???
 
Moin, Moin.
Da ich gestern zu später Stunde so nette Unterstützung gefunden habe, musste ich die Aufgabenstellung dann heute Abend doch abschliessend behandeln. Anfangs funktionierte es nicht, himitsu hatte auf die Schnelle die Aufrufkonventionen von GetSysColor() wohl nicht im Kopf: Die OR-Verknüfung des Schleifenzählers mit clSystemColor ($FF000000) ist an dieser Stelle nicht richtig - es muss einfach nur der Schleifenzähler (0..31)übergeben werden.

Für alle, die es mal gebrauchen können, hier meine "Komplettlösung" als Ausschnit einer Klasse TColorPicker:

Delphi-Quellcode:
type tSysColorRec  = record
                        Value : Integer;
                        Name : String;
                        end;

var  SysColorArray : Array [0..31] of tSysColorRec =
                       ((Value:0; Name:'clActiveBorder'),
                        (Value:0; Name:'clActiveCaption'),
                        (Value:0; Name:'clAppWorkSpace'),
                        (Value:0; Name:'clBackground'),
                        (Value:0; Name:'clBtnFace'),
                        (Value:0; Name:'clBtnHighlight'),
                        (Value:0; Name:'clBtnShadow'),
                        (Value:0; Name:'clBtnText'),
                        (Value:0; Name:'clCaptionText'),
                        (Value:0; Name:'clDefault'),
                        (Value:0; Name:'clGradientActiveCaption'),
                        (Value:0; Name:'clGradientInactiveCaption'),
                        (Value:0; Name:'clGrayText'),
                        (Value:0; Name:'clHighlight'),
                        (Value:0; Name:'clHighlightText'),
                        (Value:0; Name:'clHotLight'),
                        (Value:0; Name:'clInactiveBorder'),
                        (Value:0; Name:'clInactiveCaption'),
                        (Value:0; Name:'clInactiveCaptionText'),
                        (Value:0; Name:'clInfoBk'),
                        (Value:0; Name:'clInfoText'),
                        (Value:0; Name:'clMenu'),
                        (Value:0; Name:'clMenuBar'),
                        (Value:0; Name:'clMenuHighlight'),
                        (Value:0; Name:'clMenuText'),
                        (Value:0; Name:'clNone'),
                        (Value:0; Name:'clScrollBar'),
                        (Value:0; Name:'cl3DDkShadow'),
                        (Value:0; Name:'cl3DLight'),
                        (Value:0; Name:'clWindow'),
                        (Value:0; Name:'clWindowFrame'),
                        (Value:0; Name:'clWindowText'));

procedure TColorPicker.LoadSystemColors;
var i : Integer;
begin
  for i:= 0 to 31 do SysColorArray[i].Value:=GetSysColor(i)
end;

function TColorPicker.Color2ConstName(Color:TColor):String;

  function GetSysColorString(Color:Integer):String;
  var i : Integer;
  begin
    Result:='';
    for i:=0 to 31 do
      if Color=SysColorArray[i].Value then begin
      Result:=Result+#13+SysColorArray[i].Name;
      end;
    delete(Result,1,1);
    if Result='' then Result:='not avail'
  end;

begin
  if not(ColorToIdent(Color,Result)) then Result:=GetSysColorString(Color)
end;
Verwendung:

An passender Stelle die aktuellen Farbwerte mit LoadSystemColors einlesen, z.B. im Konstruktor der Klasse. Mit Color2ConstName() können danach TColor-Werte in den Namen der symbolischen Farbkonstante umgewandelt werden. Für die ersten 20 Namen wird ColorToIdent() der VCL genutzt, wird hier kein Eintrag gefunden, erfolgt die Suche im SysColorArray.

Wie Muetze1 bereits bemerkte, handelt es sich in vielen Fällen um eine 1:n Beziehung. Die Funktion liefert für diese Werte alle dieser Farbe zugeordneten Konstantennamen (getrennt durch #13) zurück.

Mal schauen, ob das ganze einen praktischen Nutzen hat...

himitsu 31. Mai 2008 21:41

Re: ColorToString auch für Systemfarben
 
TColor statt Integer kommt wohl etwas besser :angel:
Code:
type tSysColorRec  = record
                         Value : [color=#ff0000]TColor[/color];
                         Name : String;
                       end;
hmmm, stimmt, GetSysColor nimmt ja nur den Index entgegen und nicht (wie ich mir da wohl irgendwie dachte) die Farbkonstanten :oops:



wird bei dir immer ein TColor als RGB übergeben?

wenn nicht, also falls auch mal z.B. Konstanten übergeben werden, wäre es noch gut erstmal den übergebenen Color-Wert in RGB umzuwndeln.

Hier im Forum suchenColorToRGB ... z.B.:
Delphi-Quellcode:
Function ColorToRGB(Color: TColor): TColor;
  Var _Color: TColorRec Absolute Color;

  Begin
    If _Color.Palette = cpSystemColor Then Result := GetSysColor(Color and $FF) and $FFFFFF
    Else If _Color.Palette in [cpSystemPalette..cpLogicalPalette] Then Result := Color and $FFFFFF
    Else Result := $000000;
  End;


Delphi-Quellcode:
function TColorPicker.Color2ConstName(Color: TColor): String;
...
begin
  if (Color and $ff000000 = $ff000000) then begin
    Result := SysColorArray[Color and $1f{$ff}].Name;
  end else begin
    //Color := ColorToRGB(Color); // Systemfarbkonstanten wurden schon abgefangen
                                  // die Restlichen Farbpaletten sollte nicht stören
    if not ColorToIdent(Color, Result) then Result := GetSysColorString(Color);
  end;
end;

taaktaak 31. Mai 2008 21:53

Re: ColorToString auch für Systemfarben
 
Hallo himitsu,

TColor statt Integer? Na, ist das nicht eigentlich das gleiche? Der Wertebereich ist doch identisch.


Zitat:

wird bei dir immer ein TColor als RGB übergeben?
In meinem speziellen Fall schon, der ColorWert wird mit...

Delphi-Quellcode:
Color:=FParentImage.Canvas.Pixels[150,150];
aus einem Image gewonnen. Deine Optimierung ist vorzuziehen, da allgemeingültig :thumb:

himitsu 31. Mai 2008 22:17

Re: ColorToString auch für Systemfarben
 
Zitat:

Zitat von taaktaak
Na, ist das nicht eigentlich das gleiche? Der Wertebereich ist doch identisch.

Im Grunde ist es schon gleich, aber da Value ja eine Farbe enthält ... :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz