这种情况发生在直到XE3的所有Delphi中:
[akLeft, akTop, akRight, akBottom]
,但在它和边框之间留出空间。RecreateWnd()
只要我记得自己使用Delphi,就会因此无法使用锚点。调整表单大小,然后停靠它:重新创建窗口,您的布局被破坏。
我想知道是否有某种解决方法?
评论中提供了两种解决方法,一种是经证实且稳定但形式眨眼,另一种是实验性但可能更彻底和清洁。
我暂时不会投票给任何一个,因为其中一个是我的,我甚至不确定它是否稳定。相反,我会等待一些公众意见。
答案 0 :(得分:4)
我使用的两个选项对于底部和右侧锚点的问题都不是非常理想的:
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;
答案 1 :(得分:0)
事实证明,破坏一切的功能是UpdateAnchorRules
。 TControl
FOriginalParentSize
存储FAnchorRules
,并且它在UpdateAnchorRules()
中拥有自己的原始大小,并在父级调整大小时使用它自动调整大小。 Width
获取当前父级和当前控件Height
和FOriginalParentSize
,并将其保存到FAnchorRules
和Width
。
如果一切正常,那么在正常调整大小时没有效果,因为控件和它的父级会改变大小。
但是当控件0
由于锚定而小于零时,Windows,因此Delphi仍然认为它是UpdateAnchorRules
。如果此时调用0
,则会为原始宽度保存错误的,不一致的Width
值。在此之后,布局无法修复。
(如果未调用Width
,由于保留了原始尺寸,UpdateAnchorRules
会继续以与父CreateWindow
的正确关系进行更新。
关闭创建窗口句柄调用WM_SIZE
两次的任何事情:首先在WinAPI WM_SIZE
中,因为它在返回之前调度UpdateAnchorRules
(和CreateHandle
处理程序调用{{1 }}),第二,在句柄创建后显式在UpdateAnchorRules
中。
似乎只要我们可以在CreateHandle
期间停用UpdateAnchorRules
,我们就会成功。但是CreateHandle
中有UpdateAnchorRules
的明确调用,这意味着有人认为需要是在创建句柄后调整Anchor规则。
所以也许我错过了什么,通过禁用它会有什么破坏?
无论如何,有两种方法可以禁用FAnchorMove
:设置csLoading
或设置RecreateWnd
。第一个是不好的,因为有代码在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;
。
第二个工作,这是一个解决方案:
TControl
<强>声明强>:
我不知道通过使用csLoading set运行UpdateAnchorRules
操作会破坏其他什么。
更好的替代方法是挂钩UpdateAnchorRules
过程并专门为此目的添加另一个标志检查,但这需要完全重新实现UpdateAnchorRules
(容易在不同版本的Delphi上打破不同的原始版本UpdateAnchorRules
)或发明一些方法来调用原始的{{1}},这通常是通过用钩子重写它来销毁的。