Autor Beitrag
hRb
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 207
Erhaltene Danke: 12



BeitragVerfasst: Di 19.05.20 23:28 
Hallo,
Im Internet und Delphi-Foren findet man mehrfach folgenden Code zum Einfärben von Stringgridzeilen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, 
  ARow: Integer; Rect: TRect; State: TGridDrawState);
begin
  if not Odd(ARow) and not (gdFixed in State) then
    with StringGrid1 do
    begin
      Canvas.Brush.Color := clyellow;
      Canvas.FillRect(Rect);
      Canvas.TextOut(Rect.Left+2, Rect.Top+2, Cells[ACol, ARow]);
    end;
end;

Der Code sieht logisch aus. Bei mir jedoch ist die Zeile nicht durchgefärbt (siehe angehängtes Bild). Die Unterbrechung der Farbe lässt sich durch folgende Korrektur beheben: Left um -4 Pixel verschieben.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, 
  ARow: Integer; Rect: TRect; State: TGridDrawState);
var KorrRect: TRect;                     //eingefügt
begin
  if not Odd(ARow) and not (gdFixed in State) then
    with StringGrid1 do
    begin
        KorrRect := Rect;                //eingefügt
        KorrRect.Left:=Rect.Left-4;      //eingefügt, nur durch Korrektur -4 wird das gesamte Feld gefüllt
      Canvas.Brush.Color := clyellow;
      Canvas.FillRect(KorrRect);         //geändert
      Canvas.TextOut(Rect.Left+2, Rect.Top+2, Cells[ACol, ARow]);
    end;
end;

Kann jemand erklären warum dies so ist? Rect.Left ist doch Beginn der Zelle. Ist dies nur bei mir? Compiliere mit Delphi 10.1 Update2 Berlin
Anmerkung: Da jede Zelle einzeln eingefärbt wird, gelingt es mir auch nicht die gesamte Gridzeile einzufärben, wenn sich z.B. per Splitter das Striggrid-Gitter in die Breite gezogen wird. Geht dies überhaupt?
hRb
Einloggen, um Attachments anzusehen!
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1217
Erhaltene Danke: 102

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: Mi 20.05.20 09:21 
Hey, was für eine Rahmenbreite is denn für den Grid eingestellt? Oben im Header sieht es nach einem Pixel aus. Das kann aber auch mehr sein.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Jetzt rächt sich die Natur und tötet uns.
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 207
Erhaltene Danke: 12



BeitragVerfasst: Mi 20.05.20 10:21 
Hallo Sinspin
Zitat:
was für eine Rahmenbreite is denn für den Grid eingestellt?
Was meinst Du genau unter "Rahmenbreite"?
Folgende Parameter sind im Objektinspektor gesetzt:
Gridlinewith=1
BevelKind=bkTile (erzeugt den kleinen sichtbaren Rahmen um Stringgrid, aber auch ohne Veränderung an den Basiseinstellungen [ohne Rahmen] besteht der Effekt. )
BevelWidth=1
StringGrid liegt auf einem Panel mit alClient
Hinweis: Canvas.FillRect(Rect) füllt ohne Anpassung der Werte Top, Left, Right, Bottom nur die Zelle
Soll die senkrechte Gridline ebenfalls nicht mehr zu sehen sein, muss Rect.Right um 1 erhöht werden.
Zitat:
Da jede Zelle einzeln eingefärbt wird, gelingt es mir auch nicht die gesamte Gridzeile einzufärben,

Damit meine ich, die Befehle: Rect:Left:=0;  Rect.Right:=StringGrid.Width führen nicht zum Einfärben der gesamten Zeile (wenn Grid.width größer als die Summe aller Spaltenbreiten), sondern endet an der letzten Spalte.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18842
Erhaltene Danke: 1654

W10 x64 (Chrome, IE11)
Delphi 10.2 Ent, Oxygene, C# (VS 2015), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 20.05.20 13:12 
Ein kurzes Debugging hilft...
Des Rätsels Lösung findet sich in TStringGrid.DrawCell:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
begin
  if DefaultDrawing then
  begin
    if StyleServices.Enabled then
    begin
      ARect.Left := ARect.Left + 4;

      [...]

    end
    else
      Canvas.TextRect(ARect, ARect.Left+2, ARect.Top+2, Cells[ACol, ARow]);
  end;
  inherited DrawCell(ACol, ARow, ARect, AState);
end;

Erklären kann ich das nicht. Das ist ein Bug. Ich schaue mir das an und melde das. Dein Workaround passt also.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4247
Erhaltene Danke: 901

Win10
C#, C++ (VS 2015/17)
BeitragVerfasst: Mi 20.05.20 13:45 
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 207
Erhaltene Danke: 12



BeitragVerfasst: Do 21.05.20 00:20 
Hallo jaenicke,
Erklärung zunächst hilfreich.
Habe versucht den Code in mein Programm mit einzubauen. Ist mir jedoch nicht gelungen. Auch nach Anpassungen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
if DefaultDrawing then               // und kann erst compiliert werden mit Unit Vcl.Themes
  if StyleServices.Enabled then
    begin
      ARect.Left := ARect.Left + 4;  // unklar warum + 4, warum nicht - 4
  ...                                // steht ARect KorrRect ?

  inherited DrawCell(ACol, ARow, ARect, AState); //DrawCell (..) lässt sich nicht compilieren (unbekannt}
   // auch nicht StringGrid1.DrawCell(...
   // ARow, ACol, Rect, State sind Parameter von Stringgrid1Drawcell
   // nicht jedoch ARect und AState
Könntest Du präzisieren?
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1217
Erhaltene Danke: 102

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: Do 21.05.20 08:17 
Das ist ja auch nicht zum einbauen gedacht, sondern das ist in der Implementierung des TStringGrid in Delphi zu finden. :wink:
....und erklärt warum es zu dem von dir beobachteten Phänomen kommt.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Jetzt rächt sich die Natur und tötet uns.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4247
Erhaltene Danke: 901

Win10
C#, C++ (VS 2015/17)
BeitragVerfasst: Do 21.05.20 08:57 
@hRb: Hast du denn DefaultDrawing bei dir noch aktiviert? Weil du ja selber den Text zeichnest, kannst du es doch auf false stellen (und der volle Rect der Zelle sollte zurückgegeben werden, nur daß du dann beim TextOut (bzw. besser wäre wohl TextRect, wie es auch im TStringGrid-Code benutzt wird) noch den X-Wert dann erhöhen solltest).
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 207
Erhaltene Danke: 12



BeitragVerfasst: Do 21.05.20 21:54 
Zitat:
Hast du denn DefaultDrawing bei dir noch aktiviert?

Ja, DefaultDrawing ist true (war Voreinstellung). Allerdings vermute ich, dass meine Anwendung dies auch erfordert. Und ohne OnDrawCell werde ich wohl nicht auskommen. Denn sie erfüllt gleich mehrere Anforderungen:
1. jede zweite Zeile soll grau sein, wenn die Zeile eine Datei anzeigt 'D'
2. Zeilen die Verzeichnisse anzeigen sind immer gelb. 'V'
3. Eine kopierte Datei wird vorübergehend clLime angezeigt 'C'
4. Text wird normal linksbündig eingetragen. Spalte 4 enthält die Bytes-Länge der Datei. Diese Zahl muss also rechtsbündig stehen. Hier wollte ich nicht mit führenden Nullen auffüllen (wie in Spalte 2). Allein aus diesem Grund muss der Text neu gezeichnet werden.

In StringGrid1 habe ich den Wert probehalber auf false gesetzt und dann folgende Effekte erhalten:
1. Die Fix-Zeile, die schon in der FormCreate-Routine gefüllt wird, wird nicht angezeigt.
2. Die Schriftgröße erscheint wenigstens um eins kleiner.
3. Right vom FillRect-Aufruf scheint zu groß, denn der senkrechte Trennstrich der Zelle wird überschrieben (nicht mehr sichtbar). siehe Image1.bmp

Ich füge mal den Code ein. vielleichtwird dann deutlich was zu ändern wäre.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
{Zeilen ggf Einfärben und Spalte 4 rechtsbündig}
var c        : TColor;
    RectKorr : TRect;
begin  with StringGrid1 do begin  
//StringGrid2.TopRow:=StringGrid1.TopRow;   // synchroner Zeilenlauf nur von Grid 2 nach 1
  if Arow<=FixedRows then  exit;
  RectKorr:=Rect;
  RectKorr.Left:=Rect.Left-4;               // nur durch Korrektur -4 wird das gesamte Feld gefüllt
   if uppercase(Cells[0,ARow])='V' then c:=clyellow else
     if (Cells[0,ARow])='C' then c:=clLime  // von Grid1 nach Grid 2 copierte Datei
     else begin
      if not ((gdFixed in State) or (odd(ARow)))  //(Cells[0,ARow]='D')
        then c := clBtnFace   
        else c := clwhite;
     end;
  Canvas.Brush.Color := c;
  Canvas.FillRect(RectKorr);
  Canvas.TextOut (Rect.Left + 2, Rect.Top + 2, Cells [ACol, ARow]);

  if (gdSelected in state) then            // selektierte Zeile
    begin
      Canvas.Brush.Color := $FFCC99;       // skyBluTColor
      Canvas.FillRect(RectKorr);
      Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, Cells[aCol, aRow]);
    end;
  if (ACol=4and (Arow> StringGrid1.FixedRows) then //Spalte 4 rechtsbündig
    WriteTextAligned(TStringGrid(Sender).Canvas, Rect, taRightJustify, TStringGrid(Sender).Cells[Acol, ARow]);
endend;
Einloggen, um Attachments anzusehen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18842
Erhaltene Danke: 1654

W10 x64 (Chrome, IE11)
Delphi 10.2 Ent, Oxygene, C# (VS 2015), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 22.05.20 01:08 
Wie gesagt:
Dein Workaround ist doch in Ordnung mit der Korrektur um 4 Pixel.

Probiere es einfach noch einmal, wenn Version 10.4 draußen ist. Ich würde den Fix per Compilerdirektive auf Version bis 10.3 setzen.
ausblenden Delphi-Quelltext
1:
2:
3:
    {$IF CompilerVersion <= 33.0}
        KorrRect.Left := Rect.Left - 4;      //eingefügt, nur durch Korrektur -4 wird das gesamte Feld gefüllt
    {$IFEND}


Davon abgesehen ist ein StringGrid für den Zweck gar nicht sinnvoll. Das ist der typische Anwendungsfall einer ListView wie sie ja auch im Windows Explorer verwendet wird.

Und wenn du viel selbst zeichnen möchtest, hast du mit einer VirtualTreeView sehr umfangreiche Möglichkeiten.
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 207
Erhaltene Danke: 12



BeitragVerfasst: Mo 25.05.20 18:06 
Zitat:
Probiere es einfach noch einmal, wenn Version 10.4 draußen ist. Ich würde den Fix per Compilerdirektive auf Version bis 10.3 setzen.

Das ist natürlich die absolute Profi-Korrektur. Test kann natürlich erst irgendwann erfolgen - wenn ich überhaupt noch auf neuere Versionen umsteigen will. :D
Ich danke und schließe Thema
hRb
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18842
Erhaltene Danke: 1654

W10 x64 (Chrome, IE11)
Delphi 10.2 Ent, Oxygene, C# (VS 2015), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 26.05.20 22:44 
Jetzt ist 10.4 draußen...
Der Bug ist weg, dafür ist leider das übergebene Rect nun vollends kaputt...

Da bleibt leider nur auf einen Fix zu warten oder gleich eine ListView bzw. VirtualStringTree zu verwenden...

// EDIT:
So sieht das Rect nun aus, das man bekommt:
2020-05-27

Das liegt daran, dass das ARect dort für die Textausgabe modifiziert wird und dann an inherited übergeben wird, wo das Event OnDrawCell ausgelöst wird. Das ist der Grund weshalb es sehr schlechter Programmierstil ist die übergebenen Parameter einer Methode zu verändern. Man sollte dafür lokale Variablen nutzen. In unseren eigenen Anwendungen deklarieren wir Paremter schlicht als const, so dass das gar nicht möglich ist (und bei manchen Datentypen schneller).

// EDIT:
Hier der Link zur Bugmeldung (gemeldet unter dem Firmenlogin ;-)):
quality.embarcadero.com/browse/RSP-28821
Einloggen, um Attachments anzusehen!