Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - DBGrid Zeilen paarweise färben


kiwicht - Mi 14.03.07 08:14
Titel: DBGrid Zeilen paarweise färben
Hallo,

ich möchte in einem DBGrid die Zeilen nicht abwechselnd einfärben, sondern abhängig vom Inhalt. Das klingt jetzt erstmal einfach, ist aber "ust" kompliziert. Spalte A enthält Ziffern, jedoch nicht unique, ungefähr so:

1
1
1
2
2
3
4
4
5
5
5
5

Nun sollen die Zeilen mit den jeweils gleichen Ziffern eine Farbe erhalten, die darauf folgenden wieder eine andere - um so quasi die Blöcke gleichartiger Zeilen zu markieren.

Mein code sieht bisher folgende Lösung vor:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
  if q_zonen.FieldByName('zone').AsString <> s_lastRow then
  begin
    if col_currentCol = clWhite then
      col_CurrentCol := col_gridrow
    else
      col_currentcol := clWhite;

    s_lastRow := q_zonen.FieldByName('zone').AsString;
  end;

  (Sender As TDBGrid).Canvas.Brush.Color := col_currentCol;

  if not(gdselected in state) then
    (Sender As TDBGrid).DefaultDrawColumnCell(Rect, DataCol, Column, State);


Das funktioniert auch, jedoch nur für die Zeichnung nach dem Füllen des DBGrid - sobald ich mich bewege, ändert die Zelle (!) unter dem Cursor ihre Farbe auf die Contrafarbe.

Gibts für das Problem ne Musterlösung, oder seht ihr auf Anhieb den Denkfehler - wo kann man das noch optimieren?

Danke euch


ZeitGeist87 - Mi 14.03.07 08:21

Guten Morgen!

Indem du einfach ein Stringgrid verwendest!

http://www.delphi-forum.de/viewtopic.php?t=63885

LG
Stefan


kiwicht - Mi 14.03.07 08:43

und wenn ich das nicht will? :) Das Problem ist ja lösbar, und nur ne Frage der Technik (und ein Stringgrid wirkt sich ja auch unmittelbar auf den Umfang des Codes aus)

Trotzdem danke für deinen Tipp :)


ZeitGeist87 - Mi 14.03.07 09:03

Hmm das Ganze wird bei dir etwas komplizierter!

Du brauchst unter anderem eine Zuordnugnstabelle Wert <-> Farbe (Zweidimensionales Array würd ich hier nehmen) und eine Anzahl an Farben -> distinct count(SpalteMitDenZahlen) (evtl. auch Array).

Dann würde ich wie folgt vorgehen:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
 1. Statement absetzen
 2. Oben anfangen -> Wert holen
 3. Farbe zuordnen
 4. Zuordnungstabelle schreiben (Wert|Farbe)
 5. Zeile färben
 6. Nächste Zeile -> Wert holen
 7. Array nach Wert durchsuchen
    schon vorhanden -> Farbe aus Tabelle holen und zu 5 gehen
    neuer Wert      -> zu 3 gehen


Das Ganze muss natürlich in die OnDrawDataCell-Methode deines DBGrids.

LG
Stefan


raiguen - Mi 14.03.07 12:40

user profile iconZeitGeist87 hat folgendes geschrieben:
Hmm das Ganze wird bei dir etwas komplizierter!...

Nö, würde ich nicht so sehen ;) Der Ansatz von kiwicht geht schon in die richtige Richtung (sh. unten).

user profile iconZeitGeist87 hat folgendes geschrieben:
...Das Ganze muss natürlich in die OnDrawDataCell-Methode deines DBGrids.

Es wird dir wahrscheinlich entgangen sein, dass diese Methode (bzw das Ereiegnis) veraltet ist :
OnlineHilfe hat folgendes geschrieben:
Schreiben Sie keine Ereignisbehandlungsroutine für OnDrawDataCell. OnDrawDataCell ist veraltet und dient nur der Abwärtskompatibilität. Schreiben Sie statt dessen eine Ereignisbehandlungsroutine für OnDrawColumnCell.


So nun zum 'Problem' von kiwicht:
Hab mal in einem meiner Projekte nachgeschaut: also die OnDrawColumnCell-Routine hab ich auch nicht anderst gemacht, insofern passt die schon... kann also keinen (Denk)Fehler erkennen... col_currentCol und s_lastRow sind ja selbstredend als PRIVATE-Variable!?
HAst du evtl. noch ein OnMouseOver-Ereignis, was irgendwelche Veranlassung gibt, die Zeile neu zu zeichnen?


kiwicht - Mi 17.12.08 18:39

ganz vergessen hier zu antworten. Am Ende wars ganz einfach. Fertig sieht der Spass jetzt so aus:




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:
31:
32:
33:
34:
35:
36:
// mein eigener Proc-Kopf
procedure Tf_firmendatei.gr_firmendaten1DrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn;
  State: TGridDrawState);
begin

  // anstelle meiner KOnstanten (col_...) kann natürlich auch
 // einfach eine Farbe angegeben werden

  // Hier wird die Zeile gefärbt, wenn sie ungerade ist
  if ( ( ( Sender As TDBGrid ).DataSource.DataSet.RecNo mod 2 ) = 0 ) then
    ( Sender As TDBGrid ).Canvas.Brush.Color := u_Main.col_GridRow
  else
    (Sender As TDBGrid).Canvas.Brush.Color := clWhite;
 
 // Ist die Zelle ausgewählt, wird sie entsprechend auch anders gefärbt
  if (gdSelected in State) then
  begin
    with (Sender As TDBGrid).Canvas do
    begin
      Brush.Color := u_Main.col_GridSelectedRow;
      Font.Color := u_Main.col_GridSelectedFont;
    end// with
  end// begin

 // Und hier schließlich die Färbung abhängig vom Inhalt, die eigentliche Lösung fürs PRoblem
  if qFirmendt.FieldByName('barzahl').AsString = 'X' then
    ( Sender As TDBGrid ).Canvas.Brush.Color := col_GridWarnung
  else if qFirmendt.FieldByName('barzahl').AsString = 'Y' then
    ( Sender As TDBGrid ).Canvas.Brush.Color := col_GridWarnung
  else if qFirmendt.FieldByName('archiv').AsString = '1' then
    ( Sender As TDBGrid ).Canvas.Brush.Color := col_GridAngebot;

 // und das muss sowieso immer da sein
  (Sender As TDBGrid).DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;


welu - Mi 31.12.08 11:07

Hallo Kiwicht,

// Hier wird die Zeile gefärbt, wenn sie ungerade ist
if ( ( ( Sender As TDBGrid ).DataSource.DataSet.RecNo mod 2 ) = 0 ) then
( Sender As TDBGrid ).Canvas.Brush.Color := u_Main.col_GridRow
else
(Sender As TDBGrid).Canvas.Brush.Color := clWhite;

das sollte wohl bei SQL-Abfragen gehen, nicht aber z. B. bei XBase-Tabellen (dBase, FoxPro ...). Wenn dort ein Index ausgewählt wurde, geht RecNo meistens total durcheinander. Selbst bei nichtindizierter Tabelle erhält man für RecNo keine fortlaufenden Werte, wenn "gelöschte" (also bis zum nächsten Pack nur ausgeblendete) Sätze vorhanden sind, denn diese Sätze haben im "Hintergrund" noch ihre alte Satznummer.

Grüße
Lutz