7
votes

I want to draw on the canvas of a cell in a string grid. This is going to be on top of an image preloaded into the string grid.

What I've got

Currently instead of drawing on top of the image, I am loading a second transparent image and then painting on top of the cell. This is the code I use and it works.

procedure TfrmCavern.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
                                    Rect: TRect; State: TGridDrawState);
var
  index : integer;
  I : integer;
begin
  // Calculate the corresponding linear index
  index := LinearIndexOf(ARow, ACol);
  //Draw image referenced to cell
  StringGrid.Canvas.StretchDraw(Rect, CellDetails[index].Images.Picture.Graphic);  

  //if player present draw corresponding player image
  for I := 0 to frmWelcome.NoofPlayers - 1 do
   begin
     if index = Players[I].pIndex then StringGrid.Canvas.StretchDraw(Rect,Players[I].UserImage.Picture.Graphic);
   end;
  end;
end;

The procedure first draws the image referenced to the cell. If there is a "player" present it will then draw the player piece on top. Because the "player piece" image is a transparent .PNG image the original image underneath is still visible.

What I want

The draw back of this method is that the "player piece" is in a set position within the cell due to the image being constant. I want to be able to draw the "player piece" in a different position within the cell depending on which cell is selected. I have around 200 cells so I dont really want to manually create that many images with different positions.

What I've tried

I've tried drawing directly to the canvas of the stringgrid within the drawcell procedure but that appeared to reference the entire stringgrid rather than the current cell that was being drawn.

StringGrid.Canvas.ellipse(10,10,50,50);

I've looked but I cant seem to be able to reference the canvas of the current cell - I presume it doesn't exist?

The next thing I tried was drawing to a temporary image and then drawing the image to the cell.

TempImage.Canvas.Ellipse(10,10,50,50);
StringGrid.Canvas.StretchDraw(Rect, TempImage.Picture.Graphic);

This worked to an extent, it did draw the image to the cell, however the image had an opaque background/canvas so the cell was white with the circle on it, the image beneath was not visible. I did a bit of research but couldn't find a way to make the canvas of the image transparent.

The last thing I can think of trying is to write an algorithm to locate the top left point of the current cell and then draw direct to the canvas from there, but that could be sloggy and create issues when redrawing the stringgrid.

Can anyone see a way around my issue?

Thanks in advance, Josh

2

2 Answers

3
votes

The Rect parameter to OnDrawCell specifies the bounds of the particular cell, relative to the grid's client coordinate system. So you need to draw to coordinates that lie within this rectangle. Try something like this in your event handler:

StringGrid.Canvas.Pen.Color := clBlack;
StringGrid.Canvas.Brush.Style := bsClear;
StringGrid.Canvas.Ellipse(
  Rect.Left+5,
  Rect.Top+5,
  Rect.Left+15,
  Rect.Top+15
);
4
votes

There is only one canvas, the control's canvas. Each cell is merely a rectangle inside this canvas. It is trivial to find the position of the current cell in the canvas. Indeed, this is what the Rect parameter is for. Rect.Left is the x coordinate of the cell, and Rect.Top is the y coordinate of the cell.

Or did I misinterpret your question?