Autor Beitrag
optiman
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Sa 22.01.05 01:32 
Hallo,

das Thema ist nicht neu, ich weiß. Trotz der gelesenen Forenbeiträge bekomme ich das einfach nicht hin.

Fakten: Delphi5, TStringGrid mit RangeSelect und RowSelect auf False, Editing und DrawFocusSelected auf True.
Die Zeilen sind lang. Deshalb möchte ich die selektierte Zeile gelb einfärben. Die selektierte und editierbare Zelle (deshalb kein RowSelect) ist nicht gelb sondern rot zu färben.

OnDrawCell wird immer gerufen, wenn sich der Zelleninhalt (oder der Fokus der Zelle) geändert hat.

Ich schreibe also:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TMainForm.GridDrawCell(Sender: TObject; ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
   Grid: TStringGrid;
begin
   Grid := TStringGrid(Sender);
   if (not (gdFixed in AState)) then
   begin
      if (Grid.Row = ARow) then
         Canvas.brush.Color := clYellow;
      if (gdSelected in AState) then
         Canvas.brush.Color := clRed;
   end;
   Canvas.TextRect(ARect, ARect.Left, ARect.Top, Cells[ACol, ARow]);
end;

Die initiale Darstellung ist wie gewünscht. Klicke ich jedoch in eine neue Zeile, so wird GridDrawCell für die nun nicht mehr selektierte Zelle gerufen. Diese wird nun unfarbig. Die neu selektierte Zelle wird rot. Mit den beiden betroffenen Zeilen passiert natürlich nichts. Die erste Zeile bleibt gelb, die neu selektierte Zeile wird nicht gelb.
Muss ich selbst GridDrawCell für alle Zellen einer Zeile rufen? Oder wie?

Über einen kleinen Denkanstoß von euch würde ich mich sehr freuen.
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Sa 22.01.05 09:12 
Ich habe hier ein bisschen Source aus einer meiner Komponenten. Der dient dazu, jede zweite Zeile in einer anderen Farbe darzustellen. Das ganze ist allerdings für ein TDBGrid, sollte aber bei dir genauso funktionieren.
Das ganze passiert im DrawGridColumnCell.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
  if Zeilenfarbwechsel then begin
          if Odd(FGrid.DataSource.DataSet.RecNo) then begin // Gerade under ungerade Tabellenzeile. Das brauchst du in dieser Form natürlich nicht.
            if FGrid.Focused then begin
              if not (gdSelected in state) then begin
                FGrid.Canvas.Brush.Color := FZeilenfarbe;
              end;
            end
            else begin
              if dgAlwaysShowSelection in FGrid.Options then begin // Das hast du bei dir ausgeschaltet.
                         // Muss also umgebaut werden. Aber vielleicht kannst du genau das ausnutzen?!
                if not (gdSelected in state) then begin
                  FGrid.Canvas.Brush.Color := FZeilenfarbe;
                end;
              end
              else begin
                FGrid.Canvas.Brush.Color := FZeilenfarbe;
              end;
            end;
          end;
        end;

Ist nur ein Denkanstoß. Eventuell musst du noch DefaultDrawing auf False setzen. Probier es aus. Wenn es nich funktioniert, will ich mir das gerne nochmal im Detail ansehen und selbst prüfen. Ist aber eher eine Zeitfrage im Moment.
optiman Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Sa 22.01.05 23:05 
Titel: Lösung gefunden. Ist aber nicht gerade akademisch zu nennen.
Peter, ich danke für deine Anregungen.

Leider liegt die Sache bei einer DBGrid wohl etwas anders.
Eine StringGrid kennt die verwendeten Ereignisse und Methoden nicht.
Bei dem Abbild einer Datenbank ändert sich ja auch nie nur eine einzelne Zelle. Der Record ist dort meist die kleinste sinnvolle Einheit.
StringGrid aktualisiert immer nur die 2 Zellen, die von der Selektionsveränderung betroffen sind.
Entsprechende Methoden (InvalidateRow), um eine Zeile neu zu Zeichnen, sind in der Basisklasse vorhanden. Leider jedoch nur protected.
Da ich bisher ganz ohne eigene (oder fremde) Komponenten auskomme, möchte ich nun auch nicht damit anfangen.

Erfolgreich habe ich nun die primitive Lösung implementiert.

Die das Grid enthaltene Form bekommt zwei Variablen:
ausblenden Delphi-Quelltext
1:
2:
   OldSelectedRow: longint;
   NewSelectedRow: longint;

und in der FormCreate:
ausblenden Delphi-Quelltext
1:
2:
   OldSelectedRow := 1;
   NewSelectedRow := 1;

Das Ereignis OnCellSelect abfangen. Darin implementieren:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
Grid := TStringGrid(Sender);
if (Row <> NewSelectedRow) then
begin
   OldSelectedRow := NewSelectedRow;
   NewSelectedRow := Row;
   // Schleife über alle sichtbaren Zellen.
   for i := Grid.LeftCol to Grid.LeftCol + Grid.VisibleColCount do
   begin
      // Die nun nicht mehr selektierte Zeile neu schreiben.
      if OldSelectedRow > -1 then
         Grid.Cells[i, OldSelectedRow] := Grid.Cells[i, OldSelectedRow];
      // Die nun neu selektierte Zeile neu schreiben.
      if NewSelectedRow > -1 then
         Grid.Cells[i, NewSelectedRow] := Grid.Cells[i, NewSelectedRow];
   end;

Nun wird die OnDrawCell für alle Zellen der beiden betroffenen Zeilen gerufen. Dort steht dann:

ausblenden Delphi-Quelltext
1:
2:
3:
   ...
   if (gdSelected in AState) then
      Grid.Canvas.Brush.Color := ColorOfSelectedLineInStringGrid;


und schon ist die Zeile bunt.

Mit der Neuzuweisung für die Zellen bin ich nicht gerade glücklich.
Aber wie komme ich an die protected InvalidateRow der TCustomGrid ran, ohne die Klasse selbst abzuleiten?

Beste Grüße und viel Schnee!
Optiman