I have stuck with small problem.
Imagine two things: form, that should be covered - Cover-Form; and forms that will cover Cover-Form - Tiles.
My main goal is to cover my Cover-Form with Tiles. So it will looks like the tiles. I illustrate this idea with image below
Yellow color is a Cover-Form, brown forms - Tiles. On this image you can see that forms are positioned too close each other - there is no free space between them. That's what I need.
But when I try to reach the same effect, I just get non-satisfying result. It is presented on picture below
Second image has an offset after the last tile. It is happens because of different size of form. I don't know exactly what width my Cover-Form will have. I simply divide the whole width of Cover-Form into three parts. But if Cover-Form has width, for example, 173 pixels, each of my Tiles will have width equal 173/3=57.6 pixels, that will be round to 58, but 58*3=174 and it is bad.
Code below runs situation as on second image.
type
TTileArray = Array of Array of TPoint;
// This routine comes here from David's answer below and were changed by me
procedure EvenlySpacedTiles(PixelCountH, PixelCountV, TileCount: Integer; var ArrayOut: TTileArray);
var
X: Integer;
Y: Integer;
OldH: Integer;
OldV: Integer;
OldCount: Integer;
OldCount1: Integer;
TempInt: Integer;
begin
if (PixelCountH) or (PixelCountV) or(TileCount) = 0 then
Exit;
OldH := PixelCountH;
OldCount1 := TileCount;
for X:=Low(ArrayOut) to High(ArrayOut) do
begin
OldV := PixelCountV;
OldCount := TileCount;
TempInt := OldH div OldCount1;
Dec(OldH, TempInt);
Dec(OldCount1);
for Y:=Low(ArrayOut) to High(ArrayOut) do
begin
ArrayOut[X, Y] := Point(TempInt, OldV div OldCount);
Dec(OldV, ArrayOut[X, Y].Y);
Dec(OldCount);
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
F: TForm;
P: TForm;
Delta: Integer;
PrevLeft: Integer;
PrevTop: Integer;
X:Integer;
Y: Integer;
Arr: TTileArray;
IncLeft: Integer;
begin
Delta := 3;
F := TForm.Create(Application);
F.BorderStyle := Forms.bsNone;
F.SetBounds(0, 0, 173, 115);
F.Position := poDesktopCenter;
F.Color := $11DFEE;
F.Show;
SetLength(Arr, Delta, Delta);
EvenlySpacedTiles(F.Width, F.Height, Delta, Arr);
PrevLeft := F.Left;
PrevTop := F.Top;
IncLeft := 0;
for X:=Low(Arr) to High(Arr) do
begin
PrevTop := F.Top;
Inc(PrevLeft, IncLeft);
for Y:=Low(Arr) to High(Arr) do
begin
P := TForm.Create(Application);
P.FormStyle := fsStayOnTop;
P.BorderStyle := Forms.bsNone;
P.Color := Random($FFFFFF);//clSkyBlue;
P.Show;
P.Width := Arr[X, Y].X;
P.Height := Arr[X, Y].Y;
P.Left := PrevLeft;
P.Top := PrevTop;
P.Canvas.Rectangle(P.ClientRect);
Inc(PrevTop, Arr[X, Y].y);
IncLeft := Arr[X, Y].X;
end;
end;
end;
So there is my question: how can I adjust width of all tiles (3 per row) independently of cover form's width?
Thanks in advance.
Edited
P.S.
I modified some parts of code above. Now it works perfectly even with extremely small and large Cover-Form width - from 67 px. to 1237 px.
Of course there is a way to improve this code, but the main goal is achieved.
I think I will able to finish vertical Tiles placing tomorrow and publish this part there.
In many ways the comment by David gives me an idea how to do this. Thank you, David!
P.S.S.
I have read David's first comment diagonally, so I update code to work in another way, but the result still not good. You can see it on the picture below.
The first Tile has 57 px. width; the second one - 59 px.; the third Tile - only 31 px.
I just can't get how to place Tiles correctly using an algorithm suggested in David's comment.
P.S.S.S.
And again there is no result.
Right red line demonstrates a big size of the last tile. Each tile has width 58 px.
David wrote this:
173/3=58. 173-58=115. 115/2=58. 115-58=57. 57/1=57
I am able to calculate it in real life, but I am not able to implement it in the code.
Source code is updated.
P.S.S.S.S.
David's procedure doesn't do what it should do. Picture below illustrates it.
There are a gap between the first and the second Tile, and red line on the right side as on previous picture.
P.S.S.S.S.S.
Well, at this time the first part of my task is accomplished. The second one - is adding more tiles, but I don't sure if I really need them. And I am thankful for this to David Heffernan!! He spend so much time to explain me some things and I don't know how to say him more than simlply 'Thank you very much'. I am afraid, I am able just increase his reputation and accept his post as an answer. It really does the job!
On picture we can see the result I needed
P.S.S.S.S.S.S.
I have updated source code, so it can place tile and vertically too.
I would use a simple algorithm like this:
function EvenlySpacedColumns(PixelCount, ColumnCount: Integer): TArray<Integer>;
var
i: Integer;
begin
Assert(PixelCount>0);
Assert(ColumnCount>0);
SetLength(Result, ColumnCount);
for i := low(Result) to high(Result) do begin
Result[i] := PixelCount div ColumnCount;
dec(PixelCount, Result[i]);
dec(ColumnCount);
end;
end;
Here I use div
which in effect uses division followed by truncation. But you could equally use Round(PixelCount / ColumnCount)
if you would prefer. It's somewhat arbitrary so I personally would opt for integer arithmetic on the grounds that one should avoid floating point arithmetic if it is not necessary.