![]() |
Zeilen eines TDBGrid "Blockweise" färben
Hallo,
ich weiß, wie man Zeilen eines Grids abwechselnd färbt, aber wie mach ich das Blockweise? Ich habe ein Grid, wo immer mehrere Zeilen untereinander zu einem Vorgang gehören, jede Zeile hat eine eigene ID und mehrere Zusammen / Hintereinander die selbe VorgangsID. Unterschiedlich viele Zeilen gehören so zusammen. Dementsprechend ist die Datenmenge sortiert nach "Order by VorgangsID, ID". Jetzt möchte ich, dass das Grid nicht nach jeder Zeile sondern nach jedem Vorgang die ID wechselt. Aber wie mach ich das? Was nicht klappt
Delphi-Quellcode:
Irgendwie hab ich naiv angenommen, dass beim Zeichnen des Grids die Query einmal durchlaufen wird und das dann so funzt. Aber dem ist wahrscheinlich nicht so.
// im OnOwnerDrawCell
if GridIDChangeDetected then SwitchGridColor; SetLastGridID; // usw. procedure TCheckdaten.SwitchGridColor; begin if CurrentGridColor=Color1 then CurrentGridColor:=Color2 else CurrentGridColor:=Color1; end; procedure TCheckdaten.SetLastGridID; begin Last_VG_ID:=Quelle.FieldByName('VG_ID').AsInteger; end; function TCheckdaten.GridIDChangeDetected:Boolean; begin Result:=Last_VG_ID<>Quelle.FieldByName('VG_ID').AsInteger; end; |
AW: Zeilen eines TDBGrid "Blockweise" färben
Das Malen passiert erst bei der Anzeige (nur der sichtbare Bereich) und nicht beim Laden der Daten.
Habe Deine Idee vermutlich noch nicht so ganz verstanden, aber hier müsste irgendwo eine Änderung im Quelltext stattfinden:
Delphi-Quellcode:
procedure TCheckdaten.SwitchGridColor;
begin If GridIDChangeDetected then begin if CurrentGridColor = Color1 then CurrentGridColor := Color2 else CurrentGridColor := Color1; end; end; |
AW: Zeilen eines TDBGrid "Blockweise" färben
Wenn ich Zeilenweise Färbe, dann kann ich ja so Dinge machen wie:
Wenn (Query.FieldByName('ID').AsInterger mod 2)=0 dann Farbwechsel. Das hilft mir ja nicht, denn ich muss die Zeile der jetzt gezeichneten Celle mir der Zeile davor vergleichen, ob sich bei der VG_ID eine Änderunge ergeben hat, dann Farbwechsel. Wenn beim Zeichnen halt die Query nicht von oben nach unten durchgegangen wird hilft das ganze ja auch nicht. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Ich hoffe ich habe es richtig verstanden.
Ich mache es so:
Delphi-Quellcode:
procedure TRechnungen.DBGrid1DrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if (gdSelected in State) or (gdFocused in State) then DBGrid1.Canvas.Font.Color := clBlue; if DataModule2.Rechnung.FieldByName('Bezahlt').AsBoolean=True then Begin DBGrid1.Canvas.Brush.Color := clGray; end; if DataModule2.Rechnung.FieldByName('Bezahlt').AsBoolean=False then Begin DBGrid1.Canvas.Brush.Color := clMoneyGreen; end; DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State); end; |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hallo,
ich würde mir eine Hilfsklasse bauen, z.B. eine StringList. Die bekommt so viele Einträge wie Grid-Zeilen (DBGrid.Dataet.RowCount) Du füllst du mit einfach mit passenden Zahlen (0,1, oder sowas) für die einzelnen Blöcke, und benutzt die StringList dann im OnDrawCell. Viel einfacher hättest Du mit einem normalen TStringGrid, dort könntest du mit Objects oder eine versteckten Spalte. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hallo,
sorry die späte Meldung, war halt Wochenende, und da bleibt der Rechner aus :-D. Also prinzipiell funktioniert das schon, wie ich das oben beschrieben habe, ich hatte nur einen Denkfehler und hab die falsche ID verglichen. Das heißt ich kann die Zeilen Blockweise alternierend einfärben, zumindest beim ersten mal! Das neue Problem ist nämlich jetzt, dass die ausgewählte Zeile (gdSelected in State) wie üblich anders gefärbt ist, gehighlighted. Das ist natürlich für diese Zeile kein Problem. Aber wenn ich nun in eine andere Zeile klicke, so wird diese nun gehighlighted, aber die alte Zeile muss nun ja wieder neu gezeichnet werden und da fehlt dann halt der Kontext, da eben nur einzelne Zeilen neu gezeichnet werden und nicht das ganze Grid. Ich müsste vielleicht sowas machen wie OnSelectionChange->Grid.Repaint, aber ich hab da im Grid kein Event für gefunden. |
AW: Zeilen eines TDBGrid "Blockweise" färben
welches Grid Ereignis benutzt du DrawColumnCell ?
|
AW: Zeilen eines TDBGrid "Blockweise" färben
Zitat:
|
AW: Zeilen eines TDBGrid "Blockweise" färben
Liste der Anhänge anzeigen (Anzahl: 1)
OK, hast du mein Beispiel aus #4 probiert
Delphi-Quellcode:
So färbe ich Zeilen. Die Sortierung (Gruppen) macht ja eigentlich ein SQL-Script.
procedure TRechnungen.DBGrid1DrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if (gdSelected in State) or (gdFocused in State) then DBGrid1.Canvas.Font.Color := clBlue; if DataModule2.Rechnung.FieldByName('Bezahlt').AsBoolean=True then Begin DBGrid1.Canvas.Brush.Color := clGray; end; if DataModule2.Rechnung.FieldByName('Bezahlt').AsBoolean=False then Begin DBGrid1.Canvas.Brush.Color := clMoneyGreen; end; DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State); end; Das geht nicht nur einmal am Anfang auch beim durchklicken. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hast Du für das Programm zufällig die JVCL zur Verfügung?
Dann könnte sich ein Blick auf TJvDBGrid lohnen. Der Austausch ist einfach: Altes Grid raus, neues Grid rein, solange der Name gleich bleibt, sollte das erstmal ohne Nebenwirkungen gehen. Die Methoden für die farblische Gestaltung erscheinen mir aber deutlich leistungsfähiger. Ein Grundproblem wird aber bleiben: Beim Scrollen durch die Datenmenge, der Auswahl einer Zeile bzw. dem Aufheben der Auswahl ... muss man immer auf den Satz davor schauen, um auf die richtige Farbgestaltung zu kommen. Das wird vermutlich zu einem wilden "Gehopse" mit Dataset.Next und Dataset.Prev führen. Hab's gestern mal versucht, mir ist da keine sinnvolle und immer funktionierende Lösung eingefallen. Beim Öffnen der Datenmenge und dem vorwärtsscrollen hat's ja noch geklappt, aber rückwärts oder bei der Auswahl eines Datensatzes und folgendem Wechsel vorwärts oder rückwärts bin ich gescheitert. Was man eventuell noch versuchen könnte: Neben dem DBGrid noch ein unsichtbares Stringgrid "mitführen". Beim Lesen des Daten wird in das StringGrid je Datensatz dessen RecNo und seine Farbe als Zeile eingefügt. Scrollt man nun durch die Datenmenge, so schaut man dort nach, ob die RecNo schon vorhanden ist. Wenn ja, wird dem StringGrid der Wert für die Farbe entnommen, andernfalls muss die Farbe ermittelt werden und dann im StringGrid eine entsprechende Zeile eingefügt werden. Oder immer dann, wenn eine neue VorgangsID auftaucht wird die im StringGrid mit der entsprechenden Farbe vermerkt. Bei einem Datensatzwechsel wird dort dann nachgeschaut, welche Farbe zu vergeben ist. Das könnte im Ereignis OnDrawColumnCell realisierbar sein. Bei kleinen Datenmengen mag das insgesamt so angehen, für große Datenmengen dürfte es aber eher ungeeignet sein. Oder im DataSet eine zusätzliche Spalte einfügen für den Farbwert. Die Spalte darf halt nur nicht angezeigt werden. Dann könnte man beim Scrollen die Farbe dort entnehmen. Nur bei der erstmaligen Anzeige eines Datensatzes muss halt die Farbe erst aus dem vorherigen Datensatz ermittelt werden und dann im DataSet eingefügt werden. Bei einer ReadOnly-Datenmenge dürfte das aber auch schon wieder scheitern. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Zitat:
@Ralph: Welche Datenzugriffskomponente setzt du denn ein? |
AW: Zeilen eines TDBGrid "Blockweise" färben
Pack doch ein berechnetes Feld rein, welches den Status "leer bzw 0" (also Farbe ermitteln), "1" (Farbe 1) und "2" (Farbe 2) hat. Dann setze die Farbe anhand dieses Flags.
|
AW: Zeilen eines TDBGrid "Blockweise" färben
Für die Berechnung sind aber Informationen aus dem vorherigen Datensatz (VorgangsID) erforderlich.
Berechnet Felder beziehen sich aber (soweit ich weiß) auf den aktuellen Datensatz. Der Datensatz enthält also bereits alle zur Berechnung erforderlichen Informationen. Diese Bedingung ist hier aber nicht erfüllt. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Zitat:
@all: Danke für die bisherigen Vorschläge. Das Problem hat Uwe gut beschrieben, nicht der aktuelle Datensatz alleine bestimmt ob/wie gefärbt wird. Ich überlege jetzt (nach dem ersten Zeichnen) eine Event-Prozedur an das OnDataChange der TDatasource zu hängen. Feuert dieses, dann - weise dem OnDataChange nil zu - Komplettes Grid.Repaint - dann weise dem OnDataChange wieder die Prozedur zu (da das OnDataChange während eines Repaint ohne Ende feuert, muss man das mMn vorher ausschalten). Komme aber erst später dazu das mal zu testen, da ich gerade nicht in der Firma bin. |
AW: Zeilen eines TDBGrid "Blockweise" färben
@Uwe Raabe Danke für die verständliche Erklärung.
Könnte es eventuell mit einer temporären Tabelle(im dbGrid) mit den erforderlichen Flags gehen. Die entsprechend mit den veränderten IDs aktualisiert wird. Ich meine damit das Problem auf DB-Ebene zu lösen. Oder ist der Gedankengang wieder daneben.:oops: |
AW: Zeilen eines TDBGrid "Blockweise" färben
Zitat:
In dem Fall könntest du die Daten in ein TClientDataSet oder ein anderes InMemory-Dataset übernehmen und dabei ein zusätzliches Feld für die Farbe besetzen. Da die Übernahme sequentiell erfolgt, kann der ursprüngliche Algorithmus für das Färben verwendet werden. Das funktioniert natürlich nicht so gut, wenn die Daten im Grid verändert werden. In dem Fall kannst du aber vielleicht ein temporäre Tabelle anlegen und diese als Lookup verwenden. Die Tabelle hat nur zwei Felder (ID, Farbe), wobei ID mit der ID der Originaltabelle identisch ist. Wenn die Query eine überschaubare Datenmenge zurückliefert, kannst du nach dem Öffnen auch einfach ein Dictionary (ID, Farbe) anlegen. Es läuft darauf hinaus, daß du irgendwie für jeden Datensatz eine Farbe hinterlegst. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hallo Uwe,
jetzt hab ich Stoff zum nachdenken. Die Daten an sich können im Grid nicht verändert werden, aber sie können gefiltert oder sortiert werden, wodurch sich die Reihenfolge ändert. Ich muss mal schauen, ob man nach jeder Fileraktion oder so in zusätzlichen Feldern eines ClientDatasets (wenn ich denn darauf umstelle) die Farbwerte neu vergeben kann. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Zitat:
Gemäß Uwe sind zwar bei der Färbung einer Gruppe mehrere Datensätze relevant für die Frage ob gleiche Gruppe oder nächste. Das kann ich aber immer mit einem Merker auf den vorigen Datensatz abfangen oder? Ich muss nicht wissen, was alles kommt. Ich muss nur merken, Wert ändert sich also wechsel ich die Farbe. Dies gilt natürlich nur, wenn die Darstellung gemäß initialer Abfrage/Sortierfolge erfolgt. Dann filtern/sortieren: Hier wäre es erstmal eine Frage, was ich erreichen will. a) Gruppen/Färbung beibehalten (wie original): Visueller Effekt wäre dann, "Flatterfärbung" oder scheinbare Gruppen, obwohl durch Filterung einfach nur andere fehlen und bei Hinundher Farbwechsel dann scheinbar neue Gruppen entstehen. Der User würde das ggF. als Indikator für "unvollständige " Gruppen sehen/bemerken. Vielleicht deutlicher/besser, wenn mit hinreichend vielen Farben (mehr als 2 ) gearbeitet wird. b) ich will den "Stile" beibehalten und wende die Färbungsmechanik neu an, bei geänderter Sortierung vorzugsweise auf das neue Sortierfeld. |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hallo,
Zitat:
|
AW: Zeilen eines TDBGrid "Blockweise" färben
Zitat:
Wenn ich den Cursor/Selector zwischen den Zeilen hin und her springe, werden nur einzelne Zeilen neu gezeichnet und ich habe nicht den Bezug zu den Zeilen davor. Genau das ist mein Problem. @Jobo: Sortierung war quatsch, das Grid kann nicht sortiert werden, denn es muss ja immer ala "Order By GruppenID, EinzelID" sortiert sein, damit es überhaupt erst möglich ist zusammenhängende Blöcke zu haben. Das einzige was passieren kann ist Filterung, d.h. die Datenmenge ändert sich und das Grid müsste eigentlich komplett neu gezeichnet und gefärbt werden. Das eine weiße Zeile dann grau wird oder umgekehrt ist egal. Es geht ja nur darum den einen Block vom nächsten zu unterscheiden. Und deswegen kann dann der Übernächste Block auch wieder die selbe Farbe haben wie der erste. Ich basteln nachher in der Firma nochmal ein bisschen rum, irendwie muss das doch gehen :). |
AW: Zeilen eines TDBGrid "Blockweise" färben
Beim Zeichnen der Daten müsste das Grid doch eigentlich immer erstmal von oben nach unten durch die Datenmenge gehen.
Wenn man nun hergeht und im Ereignis AfterOpen (bzw. beim Setzen eines Filters) eine (globale) Stringliste leert und immer dann, wenn eine Zeile gezeichnet wird prüft, ob die aktuelle VorgangsID dort vorhanden ist, müsste doch ungefähr so eine Logik funktionieren:
Delphi-Quellcode:
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin if StringList.IndexOf(VorgangsID) < 0 then StringList.Add(VorgangsID); Case StringList.IndexOf(VorgangsID) Mod 2 of 0 : DBGrid1.Canvas.Brush.Color := clWhite; 1 : DBGrid1.Canvas.Brush.Color := clInfoBk; end; end; |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hmm..
Ich würde mir ne StringList nehmen und dort nach dem Name/Value Prinzip Einträge erzeugen. Die Liste wird beim OnAfterOpen des Querys gelöscht. Beim OnDrawCell wird nun in der Liste nach einem 'Name' mit der ID gesucht (StringList.NameOf()). - Wenn Nicht vorhanden, dann ein Add mit ID=NewColor hinzufügen. - Wenn Vorhanden, dann die Color (StringList.Value[]) der ID verwenden. Wenn nun gescrollt wird, wird immer die passende Farbe zur ID verwendet, egal ob rauf oder runter. Dann ist auch die Sortierung der Datenmenge egal, da die Farbe zur ID des Datensatzes geholt wird. Wenn Du die StringList auf Sorted setzt, wird auch das Suchen darin schneller. (Nur so eine Idee zur Umsetzung ;) ) |
AW: Zeilen eines TDBGrid "Blockweise" färben
Es würde auch reichen, wenn du dir die Farbe pro VorgangsID irgendwo hinterlegst.
|
AW: Zeilen eines TDBGrid "Blockweise" färben
Das klingt sehr gut. Beim erstmaligen Zeichnen wird die Farbinformation in einer Parallelstruktur gespeichert und über die VorgangsID verlinkt. Das kann dann beim Neuzeichnen einzelner Zeilen oder Zellen weiterhin benutzt werden.
Erst bei einer Filterung und somit einen anderen Aufbau des Grids muss diese Parallelstruktur aktualisiert werden. Ich glaube das habt ihr weiter oben auch schon mal gemeint, als z.B. Uwe von temporärer Tabelle o.ä. gesprochen hat. Da hab ich nicht verstanden was gemeint war, aber jetzt scheint es mir klar zu sein. Werde ich morgen gleich testen. Irgendwie will die Bahn mich heute nicht mehr in die Firma lassen :cry: |
AW: Zeilen eines TDBGrid "Blockweise" färben
Ganz simpler Ansatz:
Beim Einlesen der Daten erstellst du eine Liste der VG_IDs (z.B: Im DrawCell-Event hast du ja für den aktuellen Datensatz die VG_ID in dem entsprechenden Feld. Nun suchst du den Index dieser VG_ID in der zuvor erstellten Liste. Je nachdem ob der Index gerade oder ungerade ist (kann man leicht mit der Funktion |
AW: Zeilen eines TDBGrid "Blockweise" färben
Hallo und guten morgen,
habe jetzt erstmal den Ansatz von Delphi.Narium mit der Stringliste umgesetzt (@Uwe: Dieses Programm ist noch in D6 ohne Generics, sonst wäre dein Vorschlag noch einfacher) als einfachste Version einer Liste, arbeite halt einfach mit der ID als String. Funzt sehr gut. Auch das Aktualisieren / Neuzeichnen nach Filter-Aktionen klappt schon, oder wenn wein modales Form auf und wieder zugeht, müssen ja die davon verdeckten Zellen neue gezeichnet werden, klappt alles. Bei manchen Aktionen kommt es noch durcheinander, aber da muss ich nur noch die Stellen finden, an denen ich die Stringlist zurücksetzen muss, damit das da auch klappt, aber das krieg ich hin. Vielen lieben Dank allen Helfenden :thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:11 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz