Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   ListView - Problem beim Spaltenfärben (https://www.delphipraxis.net/193409-listview-problem-beim-spaltenfaerben.html)

e-gon 27. Jul 2017 08:47

ListView - Problem beim Spaltenfärben
 
Hallo!

Gerade bin ich auf ein mir unerklärliches Phänomen beim Färben einer Spalte eines ListViews gestoßen. Kann es sein, dass die Systemvariable clWindows während eines CustomDraws den Inhalt ändert?

Folgender Code soll die angeklickte Spalte (ListView1SortCol) mit einem hellen Gelb markieren:
Delphi-Quellcode:
procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  if ListView1SortCol=0 then ListView1.Canvas.Brush.Color:= $E4FFFF
  else ListView1.Canvas.Brush.Color:= clWindow;
end;

procedure TForm1.ListView1CustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
begin
  if ListView1SortCol=SubItem then ListView1.Canvas.Brush.Color:= $E4FFFF
  else ListView1.Canvas.Brush.Color:= clWindow;
end;
Die Spalten vor ListView1SortCol werden mit korrektem Hintergrund angezeigt, während die Spalten danach mit der gleichen Farbe wie die markierte Spalte gefärbt werden. Erstetze ich jedoch clWindow durch clWhite, funktioniert alles.

Aber clWindow sollte sich doch nicht ändern, oder?

Gruß
e-gon

e-gon 28. Jul 2017 08:59

AW: ListView - Problem beim Spaltenfärben
 
Guten Morgen!

Entweder nutze ich die falschen Suchbegriffe, dieses Phänomen tritt nur bei mir auf (mit D6 und D2009 unter Windows 7) oder es hat noch niemand entdeckt. Eine Antwort hätte ich aber dennoch gerne. Weiß wirklich niemand etwas dazu?

Damit das Nachvollziehen etwas einfacher geht, habe ich den Code erweitert. Diesen einfach in eine leere Unit kopieren, FormCreate und FormDestroy verbinden und nach der Ausführung auf die Spalten klicken.

Delphi-Quellcode:
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure ListView1CustomDrawItem(Sender: TCustomListView; Item: TListItem;
      State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem;
      SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

var
  ListView1SortCol: Integer;
  ListView1: TListView;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var ListItem: TListItem;
     ListColumn: TListColumn;
     x,y: Integer;
begin
  ListView1:= TListView.Create(Self);
  ListView1.Parent:= Form1;
  ListView1.Top:= 8;
  ListView1.Left:= 8;
  ListView1.Width:= 400;
  ListView1.OnColumnClick:= ListView1ColumnClick;
  ListView1.OnCustomDrawItem:= ListView1CustomDrawItem;
  ListView1.OnCustomDrawSubItem:= ListView1CustomDrawSubItem;

  ListView1.ViewStyle:= vsReport;
  for x:= 1 to 6 do begin
    ListColumn:= ListView1.Columns.Add;
    ListColumn.Caption:= IntToStr(x);
  end;

  for x:= 1 to 7 do begin
    ListItem:= ListView1.Items.Add;
    ListItem.Caption:= 'Zeile '+IntToStr(x);
    for y:= 1 to 6 do
      ListItem.SubItems.Add('Sub '+IntToStr(x)+'/'+IntToStr(y));
  end;
  ListView1SortCol:= -1;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ListView1.Free;
end;

procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
  ListView1SortCol:= Column.Index;
  ListView1.Repaint;
end;

procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView; Item: TListItem;
  State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  if ListView1SortCol=0 then ListView1.Canvas.Brush.Color:= $E4FFFF
  else ListView1.Canvas.Brush.Color:= clWindow;  // <- hier tritt das Problem auf, obwohl Color den richtigen Wert enthält
//  else ListView1.Canvas.Brush.Color:= clWhite;
end;

procedure TForm1.ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem;
  SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  if ListView1SortCol=SubItem then ListView1.Canvas.Brush.Color:= $E4FFFF
  else ListView1.Canvas.Brush.Color:= clWindow;  // <- hier tritt das Problem auf, obwohl Color den richtigen Wert enthält
//  else ListView1.Canvas.Brush.Color:= clWhite;  // <- hier tritt das Problem auf, obwohl Color den richtigen Wert enthält
end;

end.
Tritt das Problem bei Euch auch auf? Und falls ja, weiß jemand woran das liegt?

Gruß
e-gon

Neutral General 28. Jul 2017 10:37

AW: ListView - Problem beim Spaltenfärben
 
Also bei mir passierts auch (Delphi 7)
Was geholfen hat ist:
Delphi-Quellcode:
ColorToRGB(clWindow);

Keine Ahnung warum das passiert :gruebel:

e-gon 28. Jul 2017 12:06

AW: ListView - Problem beim Spaltenfärben
 
Hallo Neutral General,

danke für die Antwort!

Also mit
Delphi-Quellcode:
ColorToRGB(clWindow);
könnte ich leben. Aber wundern tut es mich schon. Die beiden Variablen
Delphi-Quellcode:
ListView1.Canvas.Brush.Color
und
Delphi-Quellcode:
clWindow
sind schließlich vom gleichen Typ. :gruebel:

Gruß
e-gon

Neutral General 28. Jul 2017 12:09

AW: ListView - Problem beim Spaltenfärben
 
Der einzige Unterschied ist dass in clWindow nicht die eigentliche Farbe enthalten ist sondern quasi nur eine eine Art ID für die Fensterfarbe.
ColorToRGB wandelt diese "Pseudo-Farbe" um indem es mit einer API den wahren in Windows eingestellten Farbwert für clWindow herausfindet.

Was das unterm Strich damit zu tun hat, dass clWindow dieses seltsame Verhalten hervorruft weiß ich allerdings auch nicht.
Es sollte eigentlich auch ohne ColorToRGB funktionieren denke ich.

Edit: Ich hab eine Theorie:
Die ganzen "speziellen" Farben beginnen alle mit 0xFF, statt 0x00. Wenn man dieses Byte als Alphawert deuted (was vllt. die Windows API hinter dem ListView tut), dann ist clWindow einfach nur eine komplett durchsichtige Farbe. Und wenn intern das ListView so gezeichnet wird, dass nicht nur die aktuelle Spalte mit der Farbe gezeichnet wird, sondern von Spalte X bis zum Ende dann hätte man genau das verhalten. :gruebel:

Edit2: Hab grad meine Theorie widerlegt. D.h. hab wieder keine Ahnung :mrgreen:

e-gon 28. Jul 2017 12:16

AW: ListView - Problem beim Spaltenfärben
 
Zitat:

Die ganzen "speziellen" Farben beginnen alle mit 0xFF, statt 0x00. Wenn man dieses Byte als Alphawert deuted (was vllt. die Windows API hinter dem ListView tut), dann ist clWindow einfach nur eine komplett durchsichtige Farbe. Und wenn intern das ListView so gezeichnet wird, dass nicht nur die aktuelle Spalte mit der Farbe gezeichnet wird, sondern von Spalte X bis zum Ende dann hätte man genau das verhalten.
Das wäre zumindest eine Erklärung.

e-gon 28. Jul 2017 12:29

AW: ListView - Problem beim Spaltenfärben
 
Zitat:

Hab grad meine Theorie widerlegt. D.h. hab wieder keine Ahnung
Schade eigentlich...

Jasocul 28. Jul 2017 13:03

AW: ListView - Problem beim Spaltenfärben
 
Ohne jetzt in die Tiefen einsteigen zu wollen, habe ich mir das auch mal angesehen.

Der Setter für die Farbe vergleicht, ob sich die Farbe überhaupt geändert hat. Falls nicht, macht er auch nichts und die alte Farbe bleibt erhalten. Soweit ist das ja auch ok.
Aber, TColor ist definiert als -$7FFFFFFF-1..$7FFFFFFF. clWindow ist aber $FF000005 und liegt somit außerhalb dieses Bereichs, wenn ich das richtig sehe.
Ob dann der Setter noch richtig arbeitet bei dem Farb-Vergleich, möchte ich zumindest kritisch beurteilen.
Durch das ColorToGRB wird die tatsächliche Farbe verwendet. Der Standard ist wohl clWhite ($FFFFFF). Da das innerhalb des Wertebereichs liegt, funktioniert auch der Vergleich im Setter korrekt.

Ich hab mir das wirklich nur kurz angesehen und in keinster Weise überprüft.

Wenn ich mehr Zeit hätte, würde ich das mit dem Debugger mal prüfen. Aber vielleicht hat ja ein anderer User mehr Zeit als ich. :wink:

Neutral General 28. Jul 2017 13:06

AW: ListView - Problem beim Spaltenfärben
 
Zitat:

Zitat von Jasocul (Beitrag 1377699)
Ohne jetzt in die Tiefen einsteigen zu wollen, habe ich mir das auch mal angesehen.

Habe mal statt clWindow manuell eine "zufällige" Farbe benutzt die mit $FF anfängt, aber KEINE Windows Farbe ist. Damit hat es auch funktioniert. (z.B. $FF000101)
Das ist auch was meine Theorien widerlegt hat.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:58 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