Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Selektierte Zelle im Stringgrid/Drawgrid färben
Deviljho452 - Di 24.04.12 16:27
Titel: Selektierte Zelle im Stringgrid/Drawgrid färben
Hallo liebe Community,
ich sitze seit tagen verzweifelt an der Komponente des Stringgrids bzw. an dem Drawgrid, weil ich gerne das Game of Life programmieren möchte.
Man kann wunderbar mit der Maus eine Zelle auswählen, jedoch mit welchem event (ondrawcell,onclick....) und mit welchen Befehlen im Event kann ich die selektierte Zelle färben?
Danke für jeden Gedankenstrom :)
Delphi-Laie - Di 24.04.12 16:57
Deviljho452 hat folgendes geschrieben : |
und mit welchen Befehlen im Event kann ich die selektierte Zelle färben? |
Die Farbe der Schrift jedenfalls färbe ich im OnDrawCell so:
Delphi-Quelltext
1:
| StringGrid1.canvas.Font.Color:=Farbe[ACol,ARow] |
, wobei "Farbe" ein zweidimensionales Array ist, das die Farben (im Hintergrund) speichert. Wie man den Hintergrund des Stringgrids, also dessen Zellen, färbt, weiß ich momentan nicht, vermutlich aber so ähnlich, evtl. mit Wertzuweisung an StringGrind.canvas.Pen.Color.
Narses - Di 24.04.12 17:23
Moin und :welcome: in der EE!
Schonmal in die Suche geschaut? :arrow:
STRINGGRID HINTERGRUND :les: :think: ;)
cu
Narses
Deviljho452 - Di 24.04.12 17:28
Danke Narses :)
in der SuFu hab ich natürlich schon gestöbert ;), jedoch liegt mein problem beim Klicken, also beim Färben einer Zelle via Mausklick und die SuFu liefert mir nur Quelltext und Lösungsansätze, bei denen beim Öffnen des Programms bestimmte Zellen gefärbt werden.
Ich suche einfach nur etwas wie
stringgrid1.cells[acol,arow].color:=clred :P, natürlich geht es so nicht
Moderiert von Th69: Delphi-Tags hinzugefügt
Narses - Di 24.04.12 19:12
Moin!
Deviljho452 hat folgendes geschrieben : |
jedoch liegt mein problem beim Klicken, also beim Färben einer Zelle via Mausklick |
Nein, dein Problem liegt im Verständnis der Funktionsweise einer ereignisorientierten Anwendung bzw. VCL-Komponente. ;)
Man kann keine Zelle "via Mausklick" färben, weil das String-/Draw-Grid so nicht arbeitet. Es gibt das Ereignis OnDrawCell, in dem du die Gelegenheit bekommst, das aussehen dieser speziellen Zelle selbst festzulegen. Also musst du dir in einem (zusätzlichen) Speicherbereich, der idealerweise genau so groß ist, wie das Grid selbst, merken, welche z.B. in deinem Fall (Hintergrund-)Farbe diese Zelle bekommen soll. Diese Information verwendest du dann im OnDrawCell dazu, entsprechendes zu zeichnen. :idea:
Im OnClick des Grids musst du also in dem von
Delphi-Laie bereits vorgeschlagenen 2D-Array lediglich die Farbe setzen (und ggfs. ein Neuzeichnen auslösen), das ist alles. :)
cu
Narses
Delphi-Laie - Mi 25.04.12 11:24
Deviljho452 hat folgendes geschrieben : |
Ich suche einfach nur etwas wie stringgrid1.cells[acol,arow].color:=clred :P, natürlich geht es so nicht |
Ich gebe Dir grundsätzlich recht. Das Einfärben der Zellenhintergründe und/oder Schriftfarben in Stringgrids ist m.E. verunglückt, verkompliziert, nichtintuitiv, ich weiß allerdings nicht, ob man das besser hätte lösen können. Diesbezügliche Anfragen sind in den Foren mehr oder weniger ein Dauerbrenner, das allein spricht doch schon eine deutliche Sprache. Auch ich suchte stundenlang (!) nach einer Lösung.
Narses, ich bestreite, daß diese Anfrage zu der Verallgemeinerung berechtigt, einem ein gewisses Verständnis für Ereignisorientierung abzusprechen. Gewiß wollte Deviljho452 den (Ein-)Färbbefehl in irgendeine Ereignisbehandlungsroutine oder einen Unitanfang packen. Quellcode an Stellen zu plazieren, die keinem Ereignis zugrundeliegen, ist sogar ziemlich schwierig.
Fatalerweise findet die automatische Codevervollständigung ("Code insight") - jedenfalls in meinem Delphi 4 - nur
Stringgrid1.Canvas.BrushCopy, doch die Suchfunktion hier im Forum liefert schon im zweiten Falle die Lösung für die Zellen(hintergrund)färbung:
StringGrid1.Canvas.Brush.Color:=Farbe[ACol,ARow]. Klappt jedenfalls bei mir.
Ergänzung: Daß Stringgrid und individuelle (Ein-)Färbbarkeit irgendwie auf Kriegsfuß stehen, zeigt sich auch daran, wenn man mal versucht, Schrift und Zellenhintergrund - natürlich mit verschiedenen - Farben zu versehen. Die Ergebnisse sind i.d.R. inkonsistent.
Moderiert von Th69: Delphi-Tags hinzugefügt
Deviljho452 - Mi 25.04.12 16:51
Hi Laie,
ich hab mich gestern Nacht noch etwas mit dem Problem beschäftigt und jetzt via
OnMouseDown bei Mausklick schon die Kennzeichnung des Feldes mit 'X' hinbekommen.
Daraufhin wollte ich einfach eine Schleife durchlaufen lassen und bei jeder Zelle, deren Caption X ist, soll die Hintergrundfarbe
clred werden. Ich habe dabei deinen Befehl eingebaut, jedoch verlangt er bei
[ARow,ACol] einen Array Typen o.O . Da bin ich ratlos und weiß nicht was der Debugger von mir verlangt
Moderiert von Th69: Delphi-Tags hinzugefügt
Narses - Mi 25.04.12 17:48
Moin!
Deviljho452 hat folgendes geschrieben : |
Daraufhin wollte ich einfach eine Schleife durchlaufen lassen und bei8 jeder Zelle, deren Caption X ist, soll die Hintergrundfarbe clred werden. |
Narses hat folgendes geschrieben : |
dein Problem liegt im Verständnis der Funktionsweise einer ereignisorientierten Anwendung bzw. VCL-Komponente. |
An dieser Tatsache hat sich leider noch nichts geändert. :nixweiss:
Deviljho452 hat folgendes geschrieben : |
Ich habe dabei deinen Befehl eingebaut, jedoch verlangt er bei [ARow,ACol] einen Array Typen o.O . Da bin ich ratlos und weiß nicht was der Debugger von mir verlangt |
Eine Array-Referenz, die du natürlich auch selbst anlegen und verwalten musst. :idea:
Da wohl doch leider noch zu viele Grundlagen und zu viel Verständnis für ereignisorientiertes Programmieren fehlen (wobei es völlig egal ist, ob das nun einfach oder nicht sei, es ist halt so, wie es ist), hier mal ein Beispiel für ein StringGrid:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin if (Sender as TStringGrid).Cells[ACol, ARow] <> '' then begin (Sender as TStringGrid).Canvas.Brush.Color := clRed; (Sender as TStringGrid).Canvas.FillRect(Rect); end; end; |
Damit wird jede Zelle, deren Inhalt nicht-leer ist, mit rotem Hintergrund gezeichnet (ohne Inhalt). Wenn du in den Optionen des StringGrids goEditing auf TRUE setzt, kann man das schön zur Laufzeit ausprobieren.
Der Schlüssel zum Verständnis ist: es gibt keine irgendwie geartete Anweisung, mit der man den Hintergrund einer Zelle färben kann, sondern man muss beim Zeichnen des Grids eingreifen und die gewünschten/betroffenen Zellen anders (selbst) malen. Warum? Weil du (=dein Programm) nicht wissen kannst, wann das Grid gezeichnet wird, das passiert ausserhalb deines Einflussbereiches. Deshalb musst du "von hinten durch die Brust ins Auge" und darauf reagieren, dass etwas gezeichnet werden soll.
cu
Narses
Delphi-Laie - Mi 25.04.12 22:04
Deviljho452 hat folgendes geschrieben : |
jedoch verlangt er bei [ARow,ACol] einen Array Typen o.O . Da bin ich ratlos und weiß nicht was der Debugger von mir verlangt |
array of array of TColor deklarieren (definieren) und dieses Array vor dem ersten Zugriff mit
setlength([Arrayvariable],xmax-1,ymax-1) ausreichend groß dimensionieren. Ich nannte mein Array bzw. konkreter die Arrayvariable einfach "Farbe", s.o. .
Oder, wenn die Größe für immer feststeht, gleich statisch definieren:
array[0..xmax-1,0..ymax-1] of TColor (nicht:
array[1..xmax,1..ymax], weil das
Stringgrid bei den Zeilen und Spalten auch die Indizes 0 besitzt).
Moderiert von Th69: Delphi-Tags hinzugefügt
Narses - Mi 25.04.12 23:59
Moin!
Deviljho452 hat folgendes geschrieben : |
Da bin ich ratlos und weiß nicht was |
Ich denke mittlerweile, ein StringGrid (oder sonstiges Grid) ist einfach die falsche Komponente für dich und diesen Zweck. :nixweiss:
Warum probierst du nicht mal Shapes aus? Die lassen sich prima imperativ "befingern" und sind auch nicht langsamer oder schneller, als ein Grid. :idea:
Wenn man die Shapes dynamisch auf das Formular packt, dann ist das auch relativ leicht zu handeln:
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: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46:
| uses ..., ExtCtrls; const MAX_X = 5; MAX_Y = 5; FIELDSIZE = 32; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure ShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
implementation
procedure TForm1.FormCreate(Sender: TObject); var i, j: Integer; ThisShape: TShape; begin Self.ClientWidth := (MAX_X +2) *FIELDSIZE; Self.ClientHeight := (MAX_Y +2) *FIELDSIZE; for i := 1 to MAX_Y do for j := 1 to MAX_X do begin ThisShape := TShape.Create(Self); ThisShape.Parent := Self; ThisShape.Left := j*FIELDSIZE; ThisShape.Top := i*FIELDSIZE; ThisShape.Width := FIELDSIZE; ThisShape.Height := FIELDSIZE; ThisShape.Tag := i*MAX_Y +j; ThisShape.OnMouseDown := ShapeMouseDown; end; end;
procedure TForm1.ShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Sender as TShape).Brush.Color = clWhite then (Sender as TShape).Brush.Color := clBlack else (Sender as TShape).Brush.Color := clWhite; end; |
Im Anhang das entsprechende Demo-Projekt, einfach mal ausprobieren. :les: Fragen? :gruebel: Fragen! :think:
cu
Narses
DelphiJogi - So 01.10.23 22:24
Ich experimentiere seit einiger Zeit Zellen eines StringGrids zu färben. Es will mir einfach nicht gelingen! Habe schon so einige Codebeispiele ausprobiert, ohne Erfolg. Es kann doch nicht so schwierig sein !!!
Sogar dieser einfache Code macht nicht da was er soll...
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm5.StatistikListeSparDrawCell(Sender: TObject; ACol, ARow: Integer;Rect: TRect; State: TGridDrawState); begin for i := 1 to 10 do begin If StatistikListeSpar.Cells[2, i] <> '' then begin StatistikListeSpar.RePaint; StatistikListeSpar.Canvas.Brush.Color := clRed; StatistikListeSpar.Canvas.FillRect(Rect); end; end; end; |
Moderiert von Narses: Full-Quote entfernt und Delphi-Tags hinzugefügt
mandras - Mo 02.10.23 00:48
Versuche es einmal so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm5.StatistikListeSparDrawCell(Sender: TObject; ACol, ARow: Integer;Rect: TRect; State: TGridDrawState); begin If StatistikListeSpar.Cells[2, i] <> '' then begin StatistikListeSpar.Canvas.Brush.Color := clRed; StatistikListeSpar.Canvas.FillRect(Rect); end; end; |
DrawCell wird für jede sichtbare Zelle automatisch einmal aufgerufen,
insofern sind die
for-Schleife und das
Repaint nicht sinnvoll.
Moderiert von Th69: Delphi-Tags hinzugefügt
Th69 - Mo 02.10.23 09:46
Auch das ist noch nicht ganz richtig, sondern eher so
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm5.StatistikListeSparDrawCell(Sender: TObject; ACol, ARow: Integer;Rect: TRect; State: TGridDrawState); begin if ACol = 2 and StatistikListeSpar.Cells[ACol, ARow] <> '' then begin StatistikListeSpar.Canvas.Brush.Color := clRed; StatistikListeSpar.Canvas.FillRect(Rect); end; end; |
DelphiJogi - Mo 02.10.23 19:04
Th69 hat folgendes geschrieben : |
Auch das ist noch nicht ganz richtig, sondern eher so
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| procedure TForm5.StatistikListeSparDrawCell(Sender: TObject; ACol, ARow: Integer;Rect: TRect; State: TGridDrawState); begin if ACol = 2 and StatistikListeSpar.Cells[ACol, ARow] <> '' then begin StatistikListeSpar.Canvas.Brush.Color := clRed; StatistikListeSpar.Canvas.FillRect(Rect); end; end; | |
Danke, aber so komme ich nicht weiter! Also mache ich mal einen Versuchsaufbau.
Ich lege ein StringGrid mit den StandardOptionen auf meine Form.
Erzeuge folgende DrawCell-Procedure ...
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm5.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 := clRed; Canvas.FillRect(Rect); Canvas.TextOut(Rect.Left+2, Rect.Top+2, Cells[ACol, ARow]);
end; end; |
Dieser Code soll jede zweite Zeile rot färben.
Der Aufruf der Procedure ....
Delphi-Quelltext
1:
| StringGrid1DrawCell(Sender, Acol, Arow, Rect, State); |
Ist das richtig? Was ist mit
Acol und
Arow? Müssen da nicht Parameter übergeben werden?
Moderiert von Th69: Delphi-Tags hinzugefügt
mandras - Mo 02.10.23 19:33
Kann es sein, daß Du Deine
DrawCell-Methode manuell angelegt hast und nicht über die Ereignisspalte im Formulardesigner?
Normalerweise würde man wie folgt vorgehen, um jede 2. Zeile mit einer bestimmten Farbe anzuzeigen:
Das Grid im Formular anwählen, links im Objektinspektor auf die rechte Spalte ("Ereignisse") wechseln und dann einen Doppelklick auf das weiße Eingabefeld neben "
OnDrawCell" machen.
Delphi erstellt dann das "Drumherum" (Deklaration der Prozedur am Anfang des Quellcodes, erstellen des Prozedurrumpfs, die Prozedur heißt dann automatisch zB
StringGrid1DrawCell).
Dann ergänzt Du den Prozedurrumpf mit Deinem Code (der ist übrigens korrekt, bei mir färbt er den Hintergrund jeder 2. Zeile).
Nebenbei hat Delphi die Prozedur
StringGrid1DrawCell als Ereignis des Stringgrids eingetragen.
Das bedeutet, daß
StringGrid1DrawCell nun automatisch für jede Zelle des Grids aufgerufen wird, die gezeichnet werden muß.
Ich hoffe, daß ich damit Dein Problem richtig erfaßt habe.
Moderiert von Th69: Delphi-Tags hinzugefügt
DelphiJogi - Mo 02.10.23 20:15
Vielen Dank Mandras,
das war mein Fehler.
OnDrawCell im EreignisHandler habe ich total ignoriert.
Moderiert von Th69: Delphi-Tags hinzugefügt
DelphiJogi - Mo 02.10.23 21:07
Bleibt noch eine Frage ...
Wie ist "FocusColor" des Grids zu ermitteln? Und ist die Focusfarbe auch zu ändern?
Sinspin - Fr 13.10.23 16:46
Wäre ich dein Arbeitgeber und Du würdest mir diesen Code abliefern... dann wäre ich die längste Zeit dein Arbeitgeber gewesen.
DelphiJogi hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm5.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 := clRed; Canvas.FillRect(Rect); Canvas.TextOut(Rect.Left+2, Rect.Top+2, Cells[ACol, ARow]);
end; end; | |
Das Verwenden von
with führt zu sofortiger Degradierung auf das Level eines Arbeitssuchenden.
DelphiJogi - Mi 18.10.23 17:58
Moderiert von Narses: Komplett-Zitat des vorigen Beitrags entfernt.
Dann erkläre doch Mal warum der Code so schlecht ist und wie du diesen schreiben würdest!
Übrigens ist dieser Code ein "Code-Beispiel" der nicht von mir selbst stammt.
mandras - Mi 18.10.23 23:45
with ist eine Anweisung, die böse Fehler verursachen kann, die nur schwer ins Auge stechen, siehe auch
with statement considered harmful [
https://hallvards.blogspot.com/2004/08/with-statement-considered-harmful.html].
Aus diesem Grund wurde der VCL-Sourcecode überarbeitet, um ohne
with auszukommen.
Beim Debugging ist
with ein Horror, da der Inspektor damit nicht klarkommt und man selbst die auszuwertenden Ausdrücke innerhalb eines
with anpassen muß.
In Deinem Fall zB müßtest Du um bei einem Haltepunkt "Canvas.Brush.Color" auszuwerten immer "Stringgrid1." davorschreiben.
Ansonsten finde ich die Behauptung, "
with" würde eine Kündigung rechtfertigen, etwas übertrieben :)
Moderiert von Th69: Delphi-Tags hinzugefügt
Moderiert von Th69: URL-Titel hinzugefügt.
Moderiert von Th69: Beitragsformatierung überarbeitet.
Sinspin - Do 19.10.23 18:21
Ich gehe davon aus dass nur faule und oder rücksichtslose Mitarbeiter
with verwenden, somit stellt es keinen Verlust, sondern eine Schadensminimierung dar, sich von denen schnellstmöglich zu trennen.
Ist klar, das ist drastisch, aber auch die Probleme können drastisch ausfallen wenn es um viel Geld oder Menschenleben geht. Zum Glück hat es noch keinen Fall gegeben bei dem jemand zu Schaden gekommen ist.
Um es komplett zu machen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| SgdColoredCells: TStringGrid; procedure TForm5.SgdColoredCellsDrawCell(Sender: TObject; ACol,ARow: Integer; Rect: TRect; State: TGridDrawState); begin if not Odd(ARow) and not (gdFixed in State) then begin SgdColoredCells.Canvas.Brush.Color := clRed; SgdColoredCells.Canvas.FillRect(Rect); SgdColoredCells.Canvas.TextOut(Rect.Left+2, Rect.Top+2, SgdColoredCells.Cells[ACol, ARow]); end; end; |
PS: Es gibt auch Firmen die die Zwischenablage überwachen um sicherzustellen das nicht Quelltext wild umherkopiert wird. Denn auch das ist eine ganz ordentliche Fehlerquelle bei programmieren.
Zum Beispiel beim ersetzten von Variablen oder Aufrufen. Wo dann was zuviel ersetzt wird oder was falsches mitkopiert wurde. Wenn man das alles selber schreiben muss denkt man besser mit was man macht.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!