Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 重新创建窗口时锚点被破坏的解决方法?_Delphi - Fatal编程技术网

Delphi 重新创建窗口时锚点被破坏的解决方法?

Delphi 重新创建窗口时锚点被破坏的解决方法?,delphi,Delphi,这发生在所有Delphi中,直至XE3: 创建一个表单并在其上放置一个面板。将面板锚定到[akLeft、akTop、akRight、akBottom],但在面板和边框之间留出空间 添加一个按钮,该按钮调用重新创建wnd() 运行应用程序。调整窗体大小,使面板隐藏,因为由于锚定,面板的大小小于0像素按下重新创建按钮。 重新调整窗体的大小,并注意面板的锚定已断开 只要我还记得自己使用Delphi,锚就永远无法使用。调整窗体大小,然后将其停靠:重新创建窗口,布局被破坏 我想知道是否有解决办法 更新 评

这发生在所有Delphi中,直至XE3:

  • 创建一个表单并在其上放置一个面板。将面板锚定到
    [akLeft、akTop、akRight、akBottom]
    ,但在面板和边框之间留出空间
  • 添加一个按钮,该按钮调用
    重新创建wnd()
  • 运行应用程序。调整窗体大小,使面板隐藏,因为由于锚定,面板的大小小于0像素按下重新创建按钮。
  • 重新调整窗体的大小,并注意面板的锚定已断开
  • 只要我还记得自己使用Delphi,锚就永远无法使用。调整窗体大小,然后将其停靠:重新创建窗口,布局被破坏

    我想知道是否有解决办法

    更新 评论中提供了两种变通方法,一种经过验证且稳定,但形式不稳定,另一种是实验性的,但可能更彻底、更干净


    我暂时不会投票给任何一个,因为其中一个是我的,我甚至不确定它是否稳定。相反,我将等待一些公共输入。

    我使用的两个选项都不是解决底部和右侧锚点问题的理想选项是:

  • 在调用或导致调用
    RecreateWnd()之前,再次使窗口变大,然后再将其变小。但是,在将其变小之前,必须使其可见
    
  • 设置表单的约束条件,使其不能重新调整大小,以致于无法隐藏内容
  • 例如,如果闪烁较大的窗体,请使用足够大的“高度”和“宽度”值,以避免隐藏面板:

    procedure TForm1.Button1Click(Sender: TObject);
    Var
      OldWidth, OldHeight : integer;
    begin
      OldWidth := Form1.Width;
      OldHeight := Form1.Height;
      Form1.Visible := false;
      Form1.Width := 1000;
      Form1.Height := 800;
      RecreateWnd();
      Form1.Visible := true;
      Form1.Width := OldWidth;
      Form1.Height := OldHeight;
    end;
    

    原来,破坏一切的函数是
    UpdateAnchorRules
    t控件
    FAnchorRules
    中存储原始父级大小的
    及其自身的原始大小,并使用该大小在父级调整大小时自动调整大小
    UpdateAnchorRules()
    获取当前父级大小和当前控件
    Width
    Height
    ,并将它们保存到
    中,以用于原始父级大小
    FAnchorRules

    如果一切正常工作,则在正常调整大小期间不会产生任何影响,因为控件及其父控件会相应地更改大小

    但是当控件
    Width
    由于锚定而小于零时,Windows和Delphi仍然认为它
    0
    。如果此时调用了
    UpdateAnchorRules
    ,则会保存错误的原始宽度值
    0
    。这之后,布局就无法修复了

    (如果未调用,
    Width
    由于保留了原始大小,将继续按照与父级
    Width
    的适当关系进行更新)

    任何涉及创建窗口句柄的操作都会调用
    UpdateAnchorRules
    两次:首先在WinAPI
    CreateWindow
    中,当它在返回之前调度
    WM_SIZE
    时(以及
    WM_SIZE
    处理程序调用
    UpdateAnchorRules
    ),然后,在句柄创建之后,显式地在
    CreateHandle

    似乎只要我们能够在
    CreateHandle
    期间禁用
    UpdateAnchorRules
    ,我们就会成功。但是在
    CreateHandle
    中有对
    UpdateAnchorRules
    的显式调用,这意味着有人认为在创建句柄之后需要调整锚定规则

    所以,也许我遗漏了一些东西,禁用它会使一些东西断裂

    无论如何,有两种现成的方法可以禁用
    UpdateAnchorRules
    :设置
    FAnchorMove
    或设置
    csLoading
    。第一个是不好的,因为有一个代码在
    重新创建wnd
    的中途将其清除,然后再次调用
    UpdateAnchorRules

    第二个可行,下面是一个解决方案:

    type
      TComponentHack = class helper for TComponent
      public
        procedure SetCsLoading(Value: boolean);
      end;
    
    procedure TComponentHack.SetCsLoading(Value: boolean);
    var i: integer;
    begin
      if Value then
        Self.FComponentState := Self.FComponentState + [csLoading]
      else
        Self.FComponentState := Self.FComponentState - [csLoading];
      for i := 0 to Self.ComponentCount-1 do
        if Self.Components[i] is TControl then
          TControl(Self.Components[i]).SetCsLoading(Value);
    end;
    
    procedure SafeRecreateWnd();
    begin
      MyControl.SetCsLoading(true);
      try
        MyControl.RecreateWnd(); //or any operation which triggers it -- such as docking or making the window visible first time after RecreateWnd()
      finally
        MyControl.SetCsLoading(false);
      end;
    end;
    
    免责声明

    我不知道使用csLoading set运行
    t控制
    操作还会破坏什么


    更好的替代方法是钩住
    UpdateAnchorRules
    过程,并为此专门添加另一个标志检查,但这需要完全重新实现
    UpdateAnchorRules
    (容易在不同版本的Delphi上使用不同的原始
    UpdateAnchorRules
    )或者发明一些方法来调用原始的
    UpdateAnchorRules
    ,这通常是通过用钩子重写来破坏的。

    我认为“不可能使用”有点过头了。很多情况下,表单句柄永远不会被重新创建。我不这么认为。即使你现在看起来不这么做,一个月后你做了一件会触发重新创建和爆炸的事情,你在不知不觉中引入了bug。锚是不可预测的。嗯,是的,当然,这就是为什么它们被如此频繁地使用。。。锚功能相当好,多年来一直为我和其他许多人这样做。显然,你的里程数是不同的,但你无法使用它们并不意味着其他人无法使用它们。我想知道使用一种“主”面板是否有助于解决闪光灯的问题。我指的是一个面板,设置为
    alClient
    ,包含所有内容。然后,在重新创建之前,您将放大面板而不是窗体。有些闪烁可能仍然可见,但程度可能比放大表单时要小。