Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - mehrere Zellen in einem StringGrid färben
Goaznic - Mi 14.09.11 10:35
Titel: mehrere Zellen in einem StringGrid färben
Hey.
Ich bin derzeit damit beschäftigt, einen "Crossword-Generator" zu entwickeln.
Ich habe also ein Memo, in dem Begriffe stehen. Diese Begriffe werden per Klick auf einen Button in ein StringGrid gepackt (Je Zelle ein Buchstabe, also wie bei einem Crossword --> ist ja auch logisch. :D). Position und Richtung der Ausgabe in dem Grid werden zufällig bestimmt. Und dann werden natürlich die restlichen Felder noch zufällig befüllt.
Das funktioniert ja auch schonmal alles, war ja auch recht einfach.
Aber nun habe ich noch einen weiteren Button, ich nenne ihn einfach mal "Lösung". Denn wenn man auf diesen Button klickt, soll die Lösung des Crossword angezeigt werden, und zwar so, dass alle "richtigen" Zellen (die mit den "richtigen" Buchstaben) farblich markiert/befüllt werden.
Btw.: Diese Übung soll für mich der Einstieg in OOP sein.
Also: Mein Objekt ist ja 'ne Zelle - oder auch mehrere Zellen, wenn man's genau nimmt.
Nun dachte ich mir, ich kann ja erstmal beim FormCreate jeder Zelle sowas wie einen Index zuweisen, der zu diesem Zeitpunkt 0 ist.
Und dann, wenn man das Grid mit den Begriffen füllt, sollte den entsprechenden Zellen der Index 1 zugewiesen werden. Dann haben ja alle "richtigen" Zellen den Index 1 und alle "falschen" den Index 0.
Und dann beim Klick auf "Lösung" kann das Programm ja mittels einer Schleife das Grid durchgehen und immer dann, wenn der Index = 1 ist, diese Zelle färben.
Ja. Die Idee an sich soll ja schonmal soweit richtig sein. Aber bei mir hängts noch etwas an der Umsetzung.
Ich habe erstmal eine neue Klasse deklariert:
Delphi-Quelltext
1: 2: 3: 4:
| TCellData = class color: TColor; index: Integer; end; |
Beim FormCreate muss diese dann ja erstmal aufgerufen werden, weil ja jeder Zelle der Index 0 zugewiesen werden soll:
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:
| procedure TfrmMain.FormCreate(Sender: TObject); var I: Integer; e: Integer; grdRect: TGridRect; begin with grdRect do begin Top := -1; Left := -1; Right := -1; Bottom := -1; end; grdGrid.Selection := grdRect;
for I := 0 to grdGrid.RowCount do for e := 0 to grdGrid.ColCount do begin grdGrid.Objects[I, e] := TCellData.Create; TCellData(grdGrid.Objects[I, e]).index := 0; end; end; |
Dann muss ich beim Eintrag der Buchstaben auch immer gleich den Index auf 1 setzen (hier im Beispiel genügt wohl die Richtung Rechts):
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:
| procedure TfrmMain.right(var sTerm: string); var I, k: Integer; begin bStop_process := false; repeat Application.ProcessMessages; begin iCol_StartingValue := random(grdGrid.ColCount - length(sTerm)); iRow_StartingValue := random(grdGrid.RowCount); iCol := iCol_StartingValue; bMatch := True; bOutput := false; for k := 0 to length(sTerm) - 1 do if (grdGrid.Cells[iCol + k, iRow_StartingValue] <> '') and (grdGrid.Cells[iCol + k, iRow_StartingValue] <> sTerm[k + 1]) then bMatch := false; for I := 1 to length(sTerm) do begin if bMatch = True then begin grdGrid.Cells[iCol, iRow_StartingValue] := sTerm[I]; bOutput := True; iCol := iCol + 1; grdGrid.Objects[iCol + (I - 1), iRow_StartingValue] := TCellData.Create; TCellData(grdGrid.Objects[iCol + (I - 1), iRow_StartingValue]) .index := 1; end; end; Screen.Cursor := crHourglass; end; until (bOutput = True) or (bStop_process = True); Screen.Cursor := crDefault; end; |
So. Nachdem der Index 1 sein sollte (sofern das bei mir richtig ist ...) muss ja das Ereignis btnLösungMouseDown folgen:
Ja... Da brauch ich gar keinen Quelltext kopieren jetzt, da steht eh nur wirres Zeug. Jedenfalls muss ich a ja irgendwie eine Verbindung mit grdGridDrawCell aufbauen und das klappt nicht so ganz.
Ich kopier auch mal schnell mein DrawCell hier rein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TfrmMain.grdGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin if Assigned(grdGrid.Objects[ACol, ARow]) then exit; if gdFocused in State then begin grdGrid.Canvas.Brush.color := clRed; grdGrid.Canvas.FillRect(Rect); end; end; |
Ich glaub in dem Teil ist auch alles falsch ... irgendwie komm ich damit nicht weiter.
Kann mir da jemand weiterhelfen? Wenn's denn so jetzt überhaupt verständlich war. :'D
Falls jmd den ganzen Q-Text benötigt, kann ich den auch nochmal hier posten.
Horschdware - Mi 14.09.11 11:27
Das mit deinem Index habe ich jetzt nicht ganz verstanden. Ich gehe mal davon aus, dass das, was da drin steht in Ordnung ist. Dann könnte deine Zeichenroutine so ausschauen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var s : string; sg : TStringGrid; begin sg := TStringGrid(sender); s := sg.Cells[Acol,Arow];
if not loesung_zeigen then exit;
if TCellData(sg.Objects[acol,arow]).index = 1 then sg.Canvas.Brush.color := clLime else sg.Canvas.Brush.color := clRed;
sg.Canvas.FillRect(rect); DrawText(sg.Canvas.Handle, PChar(s), Length(s), Rect, DT_LEFT) ; end; |
Dabei wird der Schalter "loesung_zeigen" durch deinen Button gesetzt. Ist der nicht drin, wird auch keine Lösung gezeigt.
Ich persönlich hätte das aber ein wenig anders gemacht, indem ich TCellData einfach hätte den korrekten Wert beinhalten lassen.
Delphi-Quelltext
1: 2: 3:
| TCellData = class correct_value : string; end; |
Dann könntest du beim Aufbau des Rätsels einfach prüfen, ob die Zelle schon belegt ist (Object[x,y] <> nil) und musst in der Zeichenroutine nur noch prüfen, ob das was gerade in der Zelle steht gleich dem ist, was in der Zelle stehen soll.
Delphi-Quelltext
1:
| if s = TCellData(sg.Objects[acol,arow]).correct_value then |
Btw: Mir fällt gerade auf, das mir nicht ganz klar wurde, wie du festhältst, welche Begriffe es zu erraten gibt in Abgrenzung zu dem, was der Benutzer eingegeben hat. (habe ich das nur übersehen?)
Goaznic - Mi 14.09.11 11:41
Also die zu erratenden Begriffe werden ja (das hab ich etwas umständlich gemacht, aber geht ja auch. :D) vom Benutzer über ein Edit-Feld eingegeben. Dann werden die in ein Memo übertragen und wenn der Benutzer fertig ist, klickt er auf einen Button. Und damit werden dann der Reihe nach alle Begriffe aus dem Memo eingefügt in das Grid. Hmm, joa ... Anders halt ich das irgendwie nicht fest. Deshalb muss ich das ja so machen, dass den "richtigen" Zellen der "Index" 1 zugewiesen wird. :D
Aber anders lässt sich das doch auch nicht umsetzen, oder? Wobei das auch eher nebensächlich wäre. Hab das ja schon so weit alles jetzt, dann versuch ich das auch so fortzuführen.
Ich versuch gleich mal das, was du da geschrieben hast, anzuwenden. Aber erstmal mach ich jetzt Mittagspause! :D :D :D
Horschdware - Mi 14.09.11 12:02
Tut mir echt leid, aber ich stehe da wohl auf dem Schlauch...
Der Spieler startet das Spiel und die zu findenden Begriffe werden in das Grid eingetragen. Aber dann sieht der Spieler doch schon, welche Begriffe es gibt... ??
Zudem funktioniert doch ein Kreuzworträtsel eher so, dass man in die einzelnen Zellen des Rätsels etwas hineinschreibt und nicht so, dass man ganze Wörter errät, die dann in ein Feld ausserhalb des Rätsels eingetragen werden.
Also entweder verstehe ich dich total falsch oder ich sollte mich mal richtig ausschlafen :lol:
Goaznic - Mi 14.09.11 12:54
Jaa, also das ist ja noch Version 1.0! :D
Ich werd das noch so ausarbeiten, dass man am Ende fertige Crosswords laden kann und so.
Aber zunächst soll es einfach erstmal nur so gehen. Weil man das in der Testphase dann besser nachvollziehen kann.
Und das ist schon so wie ein richtiges Crossword, also pro Zelle ein Buchstabe. Also zur Verdeutlichung:
Du hast eine Liste mit Begriffen.
Und daneben hast du ein Gitter mit ganz vielen Buchstaben.
Und in diesem Gitter sollst du die Begriffe aus der Liste dann finden.
So ist das ganze aufgebaut. Die Liste hab ich, weil das individuell sein soll. Der Benutzer soll halt die Wörter verwenden können, die er gern hätte.
Btw.: Ich merk grad, wenn ich das irgendwann so ausarbeite, dass man ein komplettes Rätsel laden kann, dann muss ich ja auch noch einen Such-Algorithmus schreiben.
Also wahrscheinlich werde ich das doch nicht ändern. :D
Naja, wie gesagt, es ist nur eine Übung. Ich sollte anfangs ein bisschen was über das StringGrid lernen und jetzt kam dann halt noch die Geschichte mit Zellfärbung und so dazu.
Sofern ich meinen Ausbilder richtig verstanden habe, ist das auch vorerst meine letzte Übung zu dem Grid.
Das Problem wird einfach sein, dass es zunächst ein Crossword-Generator war und jetzt auf einmal dann eher ein Crossword selbst ist. Lässt sich schwer kombinieren. :D
---
Moderiert von
Narses: Beiträge zusammengefasst---
Funktioniert aber leider doch nicht so, wie ich's mir erhofft hatte.
Ich hatte vorher mal 'ne Übung, wo das mit 'gdSelected in State' gemacht wurde und so.
Hach naja, ich frag einfach mal meinen Ausbilder.
Aber nochmal vielen Dank für die Hilfe. :)
Goaznic - Do 15.09.11 11:02
Hey, ich hab's fast geschafft! Und ich konnte einiges von dem, was du gepostet hattest (bei dem DrawCell ...) doch noch verwenden! :)
Allerdings fehlt mir nun noch der Teil, wo ich den Text wieder sichbar mache. Also das was du da wie folgt geschrieben hast:
Delphi-Quelltext
1:
| DrawText(sg.Canvas.Handle, PChar(s), Length(s), Rect, DT_LEFT); |
Kannst du mir das ein wenig erläutern?
- - - - - - - - - - - - - - - - - - - - - - -
Derzeit sieht's bei mir 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:
| procedure TfrmMain.grdGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin if not loesung_zeigen then Exit; if TCellData(grdGrid.Objects[ACol, ARow]).correct_value = True then grdGrid.Canvas.Brush.color := clLime else grdGrid.Canvas.Brush.color := clRed; grdGrid.Canvas.FillRect(Rect); DrawText(grdGrid.Canvas.Handle, pChar(), Length(), Rect, DT_LEFT) end;
procedure TfrmMain.btnSolutionMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbLeft then begin loesung_zeigen := True; grdGrid.Invalidate; end; end; |
---
Moderiert von
Narses: Beiträge zusammengefasst---
Hat sich schon erledigt. Danke. =D
Also, dann wär's das hierzu erstmal.
Nochmal vielen vielen Dank! :)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 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!