我在使用 TApplication.ModalPopupMode=pmAuto 时遇到问题,我想知道我的问题是否是由我使用 pmAuto 或 delphi 中的错误引起的。
简单用例:
动作顺序:
我使用 ComboBox 作为示例,但我猜想在 DestroyWnd 过程中保存信息并在 CreateWnd 过程中恢复信息的任何控件都无法正常工作。我测试了 TListBox,它也显示相同的行为。
这并不是真正的错误,只是处理模态时各个窗口如何相互交互的一个怪癖。
Form3首次创建时,TComboBox.CreateWnd()在 DFM 流式传输期间调用。Form3.ShowModal()第一次调用时,如果它是或不是,Form3则调用自身。好的,所以被调用,保存项目,然后被调用,恢复项目。期间重新创建 的窗口并不理想,但这次可以了。RecreateWnd()PopupModepmNoneApplication.ModalPopupModepmNoneTComboBox.DestroyWnd()TComboBox.CreateWnd()TComboBoxShowModal()
当Form3.ShowModal()第二次调用时,TComboBox.CreateWnd()会再次调用而无需先前调用TComboBox.DestroyWnd()! 由于项目尚未保存,因此无法恢复。这就是为什么它TComboBox是空的。
但为什么会出现这种情况呢?当Form2被释放时,Form3的窗口仍然与Form2的窗口相关联。第一次调用将的窗口Form3.ShowModal设置为的父/所有者窗口。当您关闭 a 时,它只是被隐藏,它的窗口仍然存在。因此,当和关闭时,它们仍然存在并链接在一起,然后当被销毁时,其所有子窗口和拥有的窗口都被销毁。 收到一条消息,将其重置为 0,而不通知其其余代码窗口正在被销毁。因此,没有机会保存其当前项目,因为没有被调用。 仅当 VCL 本身销毁窗口时调用,而不是当操作系统销毁窗口时调用。Form2Form3TFormForm2Form3Form2TComboBoxWM_NCDESTROYHandleTComboBoxDestroyWnd()DestroyWnd()
现在,你该如何解决这个问题?在释放 之前,您必须销毁 的TComboBox窗口,触发其DestroyWnd()方法Form2。诀窍是,只有在属性中启用TComboBox.DestroyWnd()该标志时才会保存项目。您可以通过几种不同的方法来实现这一目标:csRecreatingTComboBox.ControlState
TWinControl.UpdateRecreatingFlag()直接打电话TWinControl.DestroyHandle()。它们都是protected,因此您可以使用访问器类来访问它们:
type
TComboBoxAccess = class(TComboBox)
end;
Form2 := TForm2.Create(nil);
try
Form2.ShowModal;
finally
with TComboBoxAccess(Form3.ComboBox1) do
begin
UpdateRecreatingFlag(True);
DestroyHandle;
UpdateRecreatingFlag(False);
end;
Frm.Free;
end;
Form3.ShowModal;
Run Code Online (Sandbox Code Playgroud)直接打电话TWinControl.RecreateWnd()。它也是protected,因此您可以使用访问器类来访问它:
type
TComboBoxAccess = class(TComboBox)
end;
Form2 := TForm2.Create(nil);
try
Form2.ShowModal;
finally
TComboBoxAccess(Form3.ComboBox1).RecreateWnd;
Frm.Free;
end;
Form3.ShowModal;
Run Code Online (Sandbox Code Playgroud)
TComboBox直到下一次需要窗口时(在后续的ShowModal().
向窗口发送TComboBox一条CM_DESTROYHANDLE消息,让我们TWinControl为您处理一切:
Form2 := TForm2.Create(nil);
try
Form2.ShowModal;
finally
if Form3.ComboBox1.HandleAllocated then
SendMessage(Form3.ComboBox1.Handle, CM_DESTROYHANDLE, 1, 0);
Frm.Free;
end;
Form3.ShowModal;
Run Code Online (Sandbox Code Playgroud)
CM_DESTROYHANDLETWinControl.DestroyHandle()在销毁子窗口时在内部使用。当TWinControl组件收到该消息时,它会自行调用UpdateRecreatingFlag()和DestroyHandle()。
| 归档时间: |
|
| 查看次数: |
1045 次 |
| 最近记录: |