【问题标题】:Mistakes in forms' position calculations in DelphiDelphi表格位置计算错误
【发布时间】:2017-07-01 14:39:05
【问题描述】:

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

黄色是封面形式,棕色形式 - 瓷砖。在此图像中,您可以看到表单彼此之间的位置太近 - 它们之间没有可用空间。这就是我需要的。
但是当我尝试达到相同的效果时,我得到的结果并不令人满意。如下图所示

第二个图像在最后一个图块之后有一个偏移量。这是由于表格大小不同而发生的。我不确切知道我的 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 := $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;

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

提前致谢。

已编辑

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

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

附言
还是没有结果。

右红线显示最后一个瓷砖的大尺寸。每个图块的宽度为 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!他花了很多时间向我解释一些事情,而我不知道该怎么说他只是简单地说“非常感谢”。恐怕,我只能增加他的声誉并接受他的帖子作为答案。它真的很管用! 在图片上我们可以看到我需要的结果

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

【问题讨论】:

  • 173 不能被 3 整除。因此,您不能对每列使用相同的宽度。而是这样做。从 Npx 像素开始。除以 Ncol,取整。将该值用于第 0 列。从 Npx 中减去该值,然后除以 Ncol-1。将该值四舍五入并用于第 1 列。重复直到用完像素和列。
  • 另外,除非有充分的理由为了简洁而省略,否则您不会将每个图块实现为单独的表单。改用形状或其他更合适的东西。
  • @DavidHeffernan,你的意思是下一个情况,对吧?假设,我有宽度为 173 像素的 Cover-Form。我知道我应该每行放置三个 Tiles,所以我除以 173 / 3 = 57。这是每个 Tile 的宽度。然后我将 3 个 Tiles 乘以 57 得到 171。我知道 171 小于 173,根据这个事实我应该这样做:173 - 171 = 2。这是在第二个出现的最后一个 Tile 之后的大小位置图像,所以我只是增加最后一个 TIle 的宽度以完全适合 Cover-Form。你觉得这个方法怎么样?
  • @DNR,不幸的是,shapes 不是一个好的解决方案。
  • 没有。完全按照我描述的方式去做。不需要乘法。您只需要消耗大量像素,并且对于每一列,尽可能均匀地消耗它们。最终你将没有任何东西可以消费。

标签: forms delphi vcl


【解决方案1】:

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

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)。这有点武断,所以我个人会选择整数运算,因为如果没有必要,应该避免浮点运算。

【讨论】:

  • 这是一段不错的代码,但它不起作用。也许我做错了什么?请再次查看我的问题,我添加了一些信息。
  • 代码运行良好。您使用不正确。 EvenlySpacedColumns(173, 3) 产生 (57, 58, 58)。这三个值的总和是173。你如何将它融入你的代码是你的问题。我敦促你更加努力。你似乎已经停止思考你的问题了。
  • 问问自己P.SetBounds(F.Left + Arr[i] * i, F.Top, Arr[i], Round(h)) 在做什么。为什么哦,你为什么用Arr[i] * i?!!!当然,我可以为您编写代码,但这有什么意义。不要放弃。不要声明“我的代码不起作用”。问题出在你身上。答案在镜子里找到。很容易证明我提供的代码符合预期。现在您只需要弄清楚如何正确布置控件。想想!
  • 我使用Arr[i] * i 来偏移每个Tile。假设每个 Tile 是一种形式,我还能如何将它们一一放置?即使我删除了这个* i,瓷砖也没有正确放置。
  • 是的,您的代码完美运行 - 它适合数组。问题出在我的代码中,但很明显。
猜你喜欢
  • 1970-01-01
  • 2013-07-27
  • 2015-07-14
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
相关资源
最近更新 更多