1
votes

I'm using a drawgrid to display a "dungeon" map. I have an array filled with data describing what types of physical features are located in each cell. The basic layout of rooms and corridors, etc. There's a PNG for each permutation.

I'm trying to "draw" the map by drawing the appropriate PNG into each cell of the drawgrid. I can do it more or less directly using DrawGrid1.Canvas.Draw(x,y,pngImage), but figuring out the exact x,y in pixels is frustrating because of the gridlines (at least, I'm finding it frustrating), and I'm not sure what other issues I'll run into down the road.

I also tried pngImage.Draw(DrawGrid1.Canvas,Rect), but once again, I have to calculate the Rect, which really seems unnecessary as the cells and PNGs are all 40x40 pixels.

Reading related articles and examples, OnDrawCell seems to be a better way, because given ARow and ACol, the Rect for the given cell is apparently precalculated (unless I'm misinterpreting what I've read in several places). But none of the examples I've found actually show how OnDrawCell is triggered. The easy answer "when something gets drawn into a cell" doesn't really explain it much better. That's what I'm trying to do.

(I've often found this to be the case with Delphi's documentation: How is explained (not always exactly for your given use case), but when or why is left shrouded in mystery..)

Of course, there are a few other things to figure out as well, like controlling the drawgrid so it doesn't erase the PNG when a cell is clicked..

Any relevant suggestions will be greatly appreciated. TFRM

1
OnDrawCell is triggered when a cell needs to be painted, the easy answer you cite is not correct. When a cell needs to be painted is determined by the OS but you can force it to do so.Sertac Akyuz
Why not draw your pngs in OnDrawCell? I think I don't understand the question.Sertac Akyuz
I think I don't understand OnDrawCell. The only reason I'm using a grid is so that after the PNGs are drawn, the user can click on adjacent (connected) cells to "move" to them. I could probably just draw them all onto a TImage or something. Are you saying that I could just "draw" on the canvas without any particular purpose just to make OnDrawCell fire so the real drawing takes place? As noted, the question is not how, but when or why.Pete
I'm wondering what you mean by the when or why being shrouded in mystery. OnDrawCell seems perfectly obvious to me. Of course all drawing events draw to a Canvas. of course every time you tell a canvas to draw something rectangular you have to provide a Rect which contains the co-ordinates of that. Nobody in the VCL is going to automatically remember for you that your rectangle is 40x40 starting at some X,Y co-ordinates. It sounds to me what you're doing would be better to prototype in a TPaintBox and then move to your own custom control, as it sounds like you don't need a grid.Warren P
@Pete - I'm not saying your drawing will trigger an OnDrawCell. On the contrary I commented your easy answer was wrong. "When" is, as I commented, when a cell needs to be painted. That can be when the cell is first displayed, or for whatever reason displayed again (restore the window..), or when the cell is located in invalidated area. "Why" is, so that you can perform your custom drawing per cell.Sertac Akyuz

1 Answers

-1
votes

Why is figuring out exact X and Y in pixels so hard? It is actually pretty simple.

In order to get left border of your rectangle you simply multiply width of you column plus width of your gridline by number of the column. And if you have gridline on the very left of the first column then add the width of your gridline.

And in order to get right border of your rectangle simply add width of the column to the previous result.

And for calculating Y you just use height instead of width

So the code would look something like this (written from my mind and untested)

const
  CellWidth = 40;
  CellHeight = 40;
  GridLineThickness = 1;

procedure DrawCell(Row, Column: Integer; Image: Bitmap);
var Rect: TRect;
begin
  Rect.Left := ((CellWidth + GridLineThickness) * Column) + GridLineThickness;
  Rect.Right := Rect.Left + CellWidth;
  Rect.Top := ((CellHeight + GridLineThickness) * Row) + GridLineThickness;
  Rect.Bottom := Rect.Top + CellHeight;
  PaintBox1.Canvas.StretchDraw(Rect, Image);
end;

And if you want an ability to zoom in or zoom out just multiply the CellWidth and CellHeight by a zoom factor. And when being zoomed out a lot just omit rendering grid lines.