Umgang mit einem TDrawGrid

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Hallo,

ich beschäftige mich gerade mit Grids und habe mir folgenden Beispielcode für ein DrawGrid gebastelt, nachem ich diverse Tutorials durchgesehen habe:

Code: Alles auswählen

unit DGTest;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Grids,
  StdCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Pitch: TDrawGrid;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PitchDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect;
      aState: TGridDrawState);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
  pic : TBitmap;
  X,Y : Integer;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  pic := TBitmap.Create;
  pic.LoadFromFile('C:/.../Pictures/Player.bmp');
  X := 1;
  Y := 1
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 Y := Y + Pitch.RowHeights[0];
 Pitch.Invalidate
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  pic.Free;
end;
 
procedure TForm1.PitchDrawCell(Sender: TObject; aCol, aRow: Integer;
  aRect: TRect; aState: TGridDrawState);
begin
   Pitch.Canvas.Draw(X,Y,pic);
end;
 
end.
 


Der Code funktioniert und macht, was ich will (das Picture wird abwärts von einer Zelle zur nächsten bewegt). Trotzdem kommt mir das komisch vor:

Code: Alles auswählen

 Y := Y + Pitch.RowHeights[0];

Ich bewege das Bild nicht von Zelle X nach Zelle Y, sondern ich benutze das Gitternetz der Zellen eher wie ein Koordinatensystem. Außerdem kommt es mir sehr unschön vor, dass meine Koordinaten für das bmp von diesem völlig getrennt und auch noch global sind. Meine Frage daher: Benutze ich das DrawGrid ungefähr so, wie es von seinen Autoren gedacht war oder habe ich mir da ein funktionierendes, aber nichts desto trotz krummes WorkAround konstruiert? Falls ja, wie würde man ein bmp denn "korrekt" über ein DrawGrid bewegen?
Ich mag Pascal...

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Umgang mit einem TDrawGrid

Beitrag von theo »

Ich weiss nicht genau was du machen willst.
Aber kann es sein, dass du das "Draw" in Drawgrid überinterpretierst?
Es ist in erster Linie ein Grid wie ein "besseres" StringGrid, also keine allgemeine Zeichenfläche, eher eine Tabelle.

Kann sein, dass ich dich falsch oder gar nicht verstehe.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Umgang mit einem TDrawGrid

Beitrag von wp_xyz »

Im DrawCell sind die Koordinaten relativ zum Grid. Ich weiß nicht, was du mit X,Y bezwecken willst, darum lasse ich das mal weg - aber um das Bild in der linken oberen Ecke einer Zelle beginnen zu lassen musst du "Pitch.Canvas.Draw(aRect.Left, aRect.Top,pic)" aufrufen (aRect definiert die Pixelkoordinaten der Ecken der Zelle, die gerade gezeichnet wird).

Dieser Code gibt das Bild in jeder Zelle aus. Falls es nur in bestimmten erscheinen soll, hast du als Parameter die Spalten/Zeilennummer im Event erhalten und kannst so abfragen, ob es sich um die richtige Zelle für das Bild handelt.

Aber ich muss Theo recht geben, so richtig klar ist mir nicht, was du eigentlich bezwecken willst.

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Meine Idee ist folgende:

Ich programmiere ein altes Minenspiel nach (MinedOut, der Großvater von Minesweeper). Der Spieler bewegt sich über ein Raster (ich dachte, ich nehme ein Grid) und er betritt entweder ein leeres Feld oder ein Feld mit Mine (Game over). Ihm wird stets angezeigt, wieviele Minen sich um ihn herum befinden. Aus diesen Informationen versucht er sich einen minenfreien Weg zu suchen.

Ich dachte erst, ich bewege den Player über ein StringGrid, aber dann hätte ich nur Textzeichen zur Darstellung von Figuren zur Verfügung gehabt (davon gehe ich jedenfalls aus). Deswegen kam ich auf das DrawGrid. Letztlich geht es um eine Art überdimensionales Schachbrett, über das man sich schrittweise bewegt. Insofern ist eine Art Tabelle, meines Erachtens durchaus passend zur Darstellung des Spiels...
Ich mag Pascal...

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Hier das Projekt (besteht bisher fast nur aus der MainForm und das Grid ist noch ein StringGrid; Funktionalität zur Bewegung der Spielfigur ist auch noch net dabei). Aber vielleicht bekommt ihr so eine Idee, wo ich eigentlich hinwill...
Dateianhänge
MinedOut.zip
(4.7 KiB) 52-mal heruntergeladen
Ich mag Pascal...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Umgang mit einem TDrawGrid

Beitrag von wp_xyz »

Wenn du schon ein Grid nimmst, kannst du auch die im Grid eingebauten Features verwenden. Es gibt eine aktive Zelle, sie hat die Zeilen/Spalten-Nummer Grid.Row und Grid.Col. In diese Zelle würde ich ein Icon mit der Spielfigur zeichnen, in die mit Bomben ein BombenIcon, etc

Code: Alles auswählen

 
var
  icon_spieler: TBitmap;
  icon_bombe: TBitmap;
 
procedure TForm1.PitchDrawCell(Sender: TObject; ACol, ARow: Integer; AState: TGridDrawState; ARect: TRect);
begin
  if (ACol = Pitch.Col) and (ARow = Pitch.Row) then
    Pitch.Canvas.Draw(ARect.Left. ARect.Top, icon_spieler)
  else
  if HatBombe(ACol, ARow) then
    Pitch.Canvas.Draw(ARect.Left, ARect.Top, icon_bombe);
end;

Die aktive Zelle kannst du mit der Tastatur bewegen. Nachteil des Grid ist, dass es auf die Maus reagiert, was die Navigation entlang eines Pfades unmöglich macht. Deshalb musst du das MouseDown-Event abfangen.

Falls du die Tastaturinteraktion nicht verwenden willst, ist ein Grid überdimensioniert und du kannst genausogut auf einem Panel oder einer Paintbox malen,

Das DrawGrid enthält keine Daten. Deshalb musst du dir ein 2D-Array in Größe des Spielfeldes anlegen und dort abspeichern, wo sich Bomben befinden. Mein Beispiel oben benötigt eine Funktion HatBombe(), die zurückgibt, ob das Feld an der angegeben Spalte/Zeile eine Bombe enthält.

Alternativ kannst du auch ein StringGrid nehmen, da ist die Datenquelle Cells direkt eingebaut (würde ich aber nicht machen, denn Strings für einen boolschen Wert zu nehmen, finde ich als Speicherverschwendung).

P.S. Was verstehst du eigentlich unter Pitch? Ich kenne das Wort im Zusammenhang mit Tonhöhe und Abstand von Leiterbahnen.

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Danke für die Hinweise!!! Meine Lösung kam mir doch gleich so gequält vor. Ich werde in diese Richtung weiterarbeiten.

wp_xyz hat geschrieben:P.S. Was verstehst du eigentlich unter Pitch? Ich kenne das Wort im Zusammenhang mit Tonhöhe und Abstand von Leiterbahnen.
"Pitch" kann auch mit "Spielfeld" übersetzt werden.
Ich mag Pascal...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Umgang mit einem TDrawGrid

Beitrag von wp_xyz »

Hier ist eine kleine Demo, wie ich das mit einem DrawGrid machen würde
Dateianhänge
minegrid.zip
(3.79 KiB) 84-mal heruntergeladen

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Das Ding arbeitet genau so, wie ich es haben wollte! Das übertrage ich jetzt in mein Projekt und damit habe ich den Grundmechanismus für alles weitere. Dankeschön! :D
Ich mag Pascal...

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Ich muss nochmal nachfragen. Ich könnte den Code von wp_xyz zwar einfach blind verwenden, aber ich möchte ihn auch kapieren:

Code: Alles auswählen

procedure TForm1.DrawGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
  aRect: TRect; aState: TGridDrawState);
begin
 if (aCol = DrawGrid1.Col) and (aRow = DrawGrid1.Row) then     // <= Diese Zeile ist mir noch nicht ganz klar
    DrawGrid1.Canvas.Draw(aRect.Left, aRect.Top, FIcon_Spieler)
  else
  if HatBombe(aCol, aRow) then
    DrawGrid1.Canvas.Draw(aRect.Left, aRect.Top, FIcon_Bombe);
end;                 

Ich habe jetzt noch die TCustomGrid.DrawCell-Referenz bei Lazarus gefunden. Danach müssten aCol und aRow die Koordinaten jener Zelle im DrawGrid sein, welche gerade durch DrawCell gezeichnet werden soll. Und DrawGrid.Row bzw. .Col beziehen sich auf die Zelle, auf die gerade der Zellcursor zeigt (habe jetzt auch hierzu die Referenz gefunden). Die Logik ist also: Wenn gerade die Zelle gezeichnet wird, auf die der Zellcursor zeigt, dann male da das Player-Icon rein. Habe ich es jetzt geschnallt?
Ich mag Pascal...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Umgang mit einem TDrawGrid

Beitrag von wp_xyz »

Ja. Lies auch noch meinen Beitrag etwas weiter oben, da hatte ich das schon geschrieben. Das Event OnDrawCell erhält als Parameter die Zeilen/Spalten-Indexe der Zelle, die gerade gezeichnet wird, eine Menge von State-Flags (ob die gerade gezeichnete Zelle selektiert ist, oder ob es einer der FixedCells ganz links/oben ist - in dem Beispiel ausgeblendet), sowie das Rechteck mit den Pixelkoordinaten der Zellecken.

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Umgang mit einem TDrawGrid

Beitrag von Marsmännchen »

Ich hab nochmal nachgelesen. Stimmt, du hattest es schon einmal gesagt. Nur dass ich das beim ersten Lesen nicht verstanden hatte. Jetzt geht es mit meinem Projekt weiter. :D
Ich mag Pascal...

Antworten