【问题标题】:Controls in a modal Form doesn't get focus when called from onActivate of another form. Why?从另一个窗体的 onActivate 调用时,模态窗体中的控件不会获得焦点。为什么?
【发布时间】:2017-09-14 21:58:41
【问题描述】:

在某些情况下,我的应用程序会在显示另一个表单 (Form1) 后尝试自动打开某个表单 (Form2)。我正在使用onFormActivate 调用ShowModal,但是在显示第二个表单后,它的控件失去了焦点。

复制:

  1. 创建一个新的 VCL 应用程序;
  2. 创建第二个表单并将TEdit 放入其中;
  3. 在主窗体上添加一个onFormActivate 监听器;

'

procedure TForm1.FormActivate(Sender: TObject);
begin
  Form2.ShowModal;
end;

运行后,您将看到 Form2 正在显示。但是编辑没有得到焦点。 如果我在项目文件中注释MainFormOnTaskbar,它会起作用。

// Application.MainFormOnTaskbar := True;

但这不是我应该改变的。我想了解一下:为什么TEdit 会失去焦点?

【问题讨论】:

  • OnActivate 在焦点切换时发生。当您激活另一个窗口时,您正在中断焦点转移。接下来是不受支持/未定义/不可靠的行为。不要尝试解决方法,以不同的方式实施。
  • 感谢@SertacAkyuz。我认为onActivate 发生在焦点改变之后。这就是我使用onActivate 而不是onShow 的原因。

标签: delphi


【解决方案1】:

OnActivate 在焦点正在移动时被触发。中断该过程是一个非常糟糕的主意。

如果您希望OnActivate 事件触发ShowModal() 调用,您应该使用PostMessage()(或简短的TTimer)延迟它,以便消息循环可以完成处理已经在进行中的焦点转移,然后可以在安全的情况下执行ShowModal()。例如:

const
  WM_SHOWMODAL_FORM2 = WM_APP + 1;

procedure TForm1.FormActivate(Sender: TObject);
begin
  PostMessage(Handle, WM_SHOWMODAL_FORM2, 0, 0);
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
  if Message.Msg = WM_SHOWMODAL_FORM2 then
    Form2.ShowModal
  else
    inherited;
end;

【讨论】:

  • 与我实现方式的唯一区别是我使用了“消息方法”而不是覆盖 WndProc。
  • 我更喜欢覆盖WndProc(),因为它允许表单单元隐藏有关它处理的特定消息的详细信息。使用message 处理程序可能更容易编码,但它也会公开不需要向其他单元公开的信息。此外,WndProc() 在任何 message 处理程序之前首先被调用,因此覆盖 WndProc() 并避免调度表查找的开销会更有效一些。但任何一种方法都可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多