Delphi 重新创建窗口时锚点被破坏的解决方法?
这发生在所有Delphi中,直至XE3:Delphi 重新创建窗口时锚点被破坏的解决方法?,delphi,Delphi,这发生在所有Delphi中,直至XE3: 创建一个表单并在其上放置一个面板。将面板锚定到[akLeft、akTop、akRight、akBottom],但在面板和边框之间留出空间 添加一个按钮,该按钮调用重新创建wnd() 运行应用程序。调整窗体大小,使面板隐藏,因为由于锚定,面板的大小小于0像素按下重新创建按钮。 重新调整窗体的大小,并注意面板的锚定已断开 只要我还记得自己使用Delphi,锚就永远无法使用。调整窗体大小,然后将其停靠:重新创建窗口,布局被破坏 我想知道是否有解决办法 更新 评
[akLeft、akTop、akRight、akBottom]
,但在面板和边框之间留出空间重新创建wnd()
我暂时不会投票给任何一个,因为其中一个是我的,我甚至不确定它是否稳定。相反,我将等待一些公共输入。我使用的两个选项都不是解决底部和右侧锚点问题的理想选项是:
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
两次:首先在WinAPICreateWindow
中,当它在返回之前调度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
,包含所有内容。然后,在重新创建之前,您将放大面板而不是窗体。有些闪烁可能仍然可见,但程度可能比放大表单时要小。