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)
。这有点武断,所以我个人会选择整数运算,因为如果没有必要,应该避免浮点运算。
我遇到了一个小问题。
想象两个东西:形式,应该被覆盖 - 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)
。这有点武断,所以我个人会选择整数运算,因为如果没有必要,应该避免浮点运算。