Delphi 表格位置计算错误

Mistakes in forms' position calculations in Delphi

我遇到了一个小问题。
想象两个东西:形式,应该被覆盖 - Cover-Form;以及将覆盖 Cover-Form - Tiles 的表格。 我的主要目标是用 Tiles 覆盖我的 Cover-Form。所以它看起来像瓷砖。我用下面的图片来说明这个想法

黄色是 Cover-Form,棕色是 Tiles。在此图像上,您可以看到表单之间的位置太近了 - 它们之间没有空闲的 space。这就是我需要的。
但是当我试图达到同样的效果时,我得到的结果并不令人满意。如下图所示

第二张图片在最后一张图块之后有一个偏移量。这是因为表格的大小不同而发生的。我不知道我的 Cover-Form 的确切宽度。我简单地将 Cover-Form 的整个宽度分为三部分。但是如果 Cover-Form 有宽度,例如 173 像素,我的每个 Tiles 的宽度将等于 173/3=57.6 像素,这将四舍五入为 58,但是 58*3=174 是不好的。

下面的代码运行情况与第二张图片相同。

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 := DFEE;
  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;

所以我的问题是:如何独立于封面表单的宽度调整所有图块的宽度(每行 3 个)?

提前致谢。

已编辑

P.S. 我修改了上面的部分代码。现在,即使 Cover-Form 的宽度非常小和非常大 - 从 67 像素起,它也能完美工作。到 1237 像素。 当然有办法改进这段代码,但主要目标已经实现。 我想我明天就能完成垂直 Tiles 的放置并发布这部分。
在许多方面,大卫的评论让我知道如何做到这一点。谢谢你,大卫!

P.S.S.
我已经对角阅读了大卫的第一条评论,所以我更新代码以另一种方式工作,但结果仍然不好。你可以在下面的图片上看到它。
第一个 Tile 有 57 像素。宽度;第二个 - 59 px.;第三个图块 - 只有 31 像素。
我只是不知道如何使用 David 评论中建议的算法正确放置 Tiles。

P.S.S.S.
再次没有结果。

右边的红线展示了最后一块瓷砖的大尺寸。每个图块的宽度为 58 像素。
大卫写道:

173/3=58. 173-58=115. 115/2=58. 115-58=57. 57/1=57

我在现实生活中可以计算,但是我无法在代码中实现。
源代码已更新。

P.S.S.S.S.
大卫的程序没有做它应该做的事。下图说明了这一点。

第一个和第二个 Tile 之间有间隙,右侧有红线,如上图所示。

P.S.S.S.S.S.
好了,这时候我的第一部分任务就完成了。第二个 - 添加更多的瓷砖,但我不确定我是否真的需要它们。我为此向 David Heffernan 表示感谢!!他花了很多时间向我解释一些事情,我不知道如何简单地向他解释 'Thank you very much'。恐怕,我只能增加他的声誉并接受他的 post 作为答案。它真的很管用! 在图片上我们可以看到我需要的结果

P.S.S.S.S.S.S.
我已经更新了源代码,所以它也可以平铺和垂直放置。

我会使用这样一个简单的算法:

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;

这里我使用 div,它实际上使用了先除后截的方法。但如果您愿意,您同样可以使用 Round(PixelCount / ColumnCount)。这有点武断,所以我个人会选择整数运算,因为如果没有必要,应该避免浮点运算。