使用 ModalResult 退出表单

发布于 2024-11-08 16:32:14 字数 742 浏览 0 评论 0原文

我有一堆表单,我想将它们自动化,以便它们可以自行打开和关闭。

我知道如何打开它们(通过 OnActivate 函数),但我在关闭它们时遇到问题。

例如,我有

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  inherited;
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      ModalResult := mrOK;
    end;    
end;

一个运行函数。我想在函数运行后关闭窗口,这就是 ModalResult 应该做的。

(我还尝试在 RunBtnClick 过程的最后添加 ModalResult 行,但这也不起作用)

并且我正在创建这样的表单:

ProgForm := TProgressForm.Create(Self, FModItem);
Self.Visible := False;
try
 if ProgForm.ShowModal = mrOK then
  begin
    Left := ProgForm.Left;
    Top := ProgForm.Top;
  end;

我已经能够创建按钮来关闭表单通过将 mrOK 添加到对象检查器中的模态结果中,但我似乎无法明确执行此操作

有人能明白为什么它不起作用吗?

谢谢

I have a bunch of forms and I want to automate them so they would open and close by themselves.

I know how to get them to open (by having an OnActivate function), but I'm having trouble closing them.

So, for example, I have

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  inherited;
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      ModalResult := mrOK;
    end;    
end;

which runs a function. I want to close the window after the function has been run, which is what ModalResult should do.

(I've also tried adding the ModalResult line at the very end of the RunBtnClick procedure, but that didn't work either)

and I'm creating the form like this:

ProgForm := TProgressForm.Create(Self, FModItem);
Self.Visible := False;
try
 if ProgForm.ShowModal = mrOK then
  begin
    Left := ProgForm.Left;
    Top := ProgForm.Top;
  end;

I've been able to create buttons to close the form just by adding mrOK to the Modal Result in Object Inspector, but I can't seem to do it explicitly

Can anyone see why it's not working?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

寄与心 2024-11-15 16:32:14

不起作用的原因是,在显示表单之后、开始检查对 ModalResult 的更改之前,VCL 在 TCustomForm.ShowModal 中主动将 ModalResult 设置为 0。所以在 OnActivate 和 OnShow 中,你太早了。

解决方案是延迟通知。这可以通过 PostMessage 来完成,如下所示:

const
  UM_ACTIVATED = WM_USER + 1;

type
  TProgressForm = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    procedure UMActivated(var Message: TMessage); message UM_ACTIVATED;
  end;

...

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  PostMessage(Handle, UM_ACTIVATED, 0, 0);
end;

procedure TProgressForm.UMActivated(var Message: TMessage);
begin
  { Your code here }
  ModalResult := mrOk;
end;

来源:NLDelphi< /a>

The reason for not working is that the VCL actively sets ModalResult to 0 in TCustomForm.ShowModal áfter showing the form, but prior to starting checking changes to ModalResult. So in OnActivate and in OnShow, you are to early.

The solution is to delay the notification. This can be done by a PostMessage, as follows:

const
  UM_ACTIVATED = WM_USER + 1;

type
  TProgressForm = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    procedure UMActivated(var Message: TMessage); message UM_ACTIVATED;
  end;

...

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  PostMessage(Handle, UM_ACTIVATED, 0, 0);
end;

procedure TProgressForm.UMActivated(var Message: TMessage);
begin
  { Your code here }
  ModalResult := mrOk;
end;

Source: NLDelphi

情徒 2024-11-15 16:32:14

我将重写 ShowModal 并执行您现在在 OnActvate 中执行的测试。这有两大优点:

  • 如果不需要显示,则根本不显示表单。从 OnActivate 启动表单关闭会导致表单在屏幕上“闪烁”:它会显示并立即关闭。
  • 不依赖于不受您控制的代码。您不再关心祖先 ShowModal 中的操作顺序,因为只有在需要实际显示表单时才调用它。

当然,以这种方式使用 GUI 元素(表单)有点代码味道,因为它基本上使用 GUI 而不需要用户交互。毫无疑问,可以将其重构为使用一个中间函数,该函数返回 mrOk 并执行 RunBtnClick() 的操作,而无需 GUI,并创建 Form仅在需要时。我想这是一种成本效益的情况。

代码:

TMyForm = class(TForm)
....
public
  function ShowModal:Integer;override;
end;

function TMyForm.ShowModal:Integer;
begin
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      Result := mrOK;
    end
  else
    Result := inherited ShowModal;
end;

I'd override ShowModal and do the tests you now do in OnActvate from over there. This has two big advantages:

  • Doesn't show the form at all if it doesn't need to be shown. Initiating the form shutdown from OnActivate causes the form to "flicker" on screen: It's shown and immediately taken down.
  • Doesn't rely on code that's not under your control. You no longer care about the order of operation in the ancestor ShowModal, because you only call it if the form needs to actually be shown.

Of course, using a GUI element (a form) this way is a bit of code smell because it basically uses a GUI without the need for user interaction. This can undoubtedly be refactored to use an intermediary function that returns mrOk and does what RunBtnClick() does without needing the GUI, and creates the Form only if needed. I guess it's a cost-benefit kind of situation.

Code:

TMyForm = class(TForm)
....
public
  function ShowModal:Integer;override;
end;

function TMyForm.ShowModal:Integer;
begin
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      Result := mrOK;
    end
  else
    Result := inherited ShowModal;
end;
柏拉图鍀咏恒 2024-11-15 16:32:14

OnActivate 事件在 TCustomForm.ShowModal 中的 ModalResult 重置为 mrNone 之前触发。这意味着 OnActivate 处理程序中的 ModalResult 更改将被忽略。

  function TCustomForm.ShowModal: Integer;
  Show;
  try
    SendMessage(Handle, CM_ACTIVATE, 0, 0);  << Your onActivate is called here
    ModalResult := 0; << ModalResult is reset

The OnActivate event is triggered before the ModalResult is reset to mrNone in TCustomForm.ShowModal. This means that changing ModalResult in your OnActivate handler is ignored.

  function TCustomForm.ShowModal: Integer;
  Show;
  try
    SendMessage(Handle, CM_ACTIVATE, 0, 0);  << Your onActivate is called here
    ModalResult := 0; << ModalResult is reset
把人绕傻吧 2024-11-15 16:32:14

查看 TCustomForm.ShowModal(在 forms.pas 内):直到发送 CM_ACTIVATE 消息之后(所述消息触发您的 OnActivate 调用),才首先检查 ModalResult;事实上,在 OnActivate 调用返回后,它立即设置为 0,因此您的作业不起作用也就不足为奇了。

我不想对此搞得太混乱(您的代码肯定无法通过气味测试),但您可以尝试添加类似以下内容:

if ModalResult=0 then 
     SendMessage(Handle, CM_ACTIVATE, 0, 0);

到事件处理程序的顶部。

Look at TCustomForm.ShowModal (inside forms.pas): ModalResult is not first checked until after the CM_ACTIVATE message is sent (said message triggers your OnActivate call); in fact, it's set to 0 immediately after your OnActivate call returns, so it's no wonder your assignment isn't working.

I don't want to mess too much with this (your code definitely fails the smell test), but you could try adding something like:

if ModalResult=0 then 
     SendMessage(Handle, CM_ACTIVATE, 0, 0);

to the top of your event handler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文