我有一个显示长操作进度的模态表单。当表单的OnActivate事件被触发时,该操作被触发。
procedure TMyForm.FormActivate(Sender:TObject);
begin
Start;
end;
表单有一个取消按钮,ModalResult属性设置为mrCancel,OnClick处理程序设置一个导致操作结束的标志。
procedure TMyForm.CancelButtonClick(Sender: TObject);
begin
FCancel := True;
end;
当我单击取消按钮时,它会按预期停止操作,但无法关闭表单。我怀疑这是因为OnActivate处理程序阻止了表单关闭。第二次点击按钮确实关闭了表单。我试着调用close并发送了一条wm_close消息,但似乎什么都不起作用。有人有什么建议可以让表格在第一次点击时做出回应吗?也许我可以使用另一个事件来代替OnActivate?
我知道会建议将操作转移到线程。由于大量的遗留代码写得不好,这在目前是不可能的。
在下文中,我将假设消息可能是通过在任务中调用Application.ProcessMessages
来处理的。
让我们来看看相关的代码ShowModal
:
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
repeat
Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
SendMessage
调用导致OnActivate
事件触发。在您的代码中,然后启动任务,直到任务完成才返回。您已指定给ModalResult
的时间点。但是等一下,上面摘录的下一行将ModalResult
设置回0
,因此您的设置将丢失。因此,进入了模式消息循环,您需要再次分配给ModalResult
以关闭表单。
这里的底线是,在进入模式消息循环之前不能执行任务。一种解决方案是将长时间运行的任务放在一个单独的线程中。如果您无法做到这一点,可以在OnActivate
事件处理程序中向表单发布消息。通过启动任务来响应事件。此时,模式消息循环将运行,设置ModalResult
将关闭表单。