【问题标题】:Delphi - Application main form gets focussed incorrectlyDelphi - 应用程序主窗体聚焦不正确
【发布时间】:2017-11-09 11:09:21
【问题描述】:

在我的应用程序的两个部分中,主窗体在错误的时刻获得了焦点:

错误 1。从特定打印机表单中单击“确定”时。

  1. 我打开一个 FastReports PDF 预览 - 这是第一个弹出窗口。该弹出窗口未在任务栏中单独显示。这种形式是模态的。
  2. 然后我点击打印,
  3. 这会打开另一个带有标准打印选项的窗口。
  4. 然后我单击属性- 打开驱动程序的特定窗体。我更改了双重打印设置。
  5. 当我单击“确定”时,预览表单 (1) 应该被聚焦,但 主表单被置于前面。因为预览表单仍然是模态的,所以很难回到预览表单。只有通过随机点击,预览表单才会再次获得焦点。


Bug 2. 单击或拖动此特定滚动框会使主窗体聚焦

  1. 此窗口处于活动状态。这是 Windows 任务栏中的一个单独窗口,不是模态的。此表单上有一个 gnostice pdf 查看器。
  2. 当我单击scrollbox 开始拖动时,主窗体被带到前面。当我继续拖动时,pdf 表单的滚动仍在继续。此外,鼠标附近的工具提示会指示当前显示的页面。

我想解决这个奇怪的行为。所以,我的问题是:


什么可能导致这些聚焦错误?


关于申请:

  • 我已经注意到:弹出表单似乎有点太大,您可以在此处看到:
  • 查看编辑
  • 有些表单是 MDI 子表单。
  • 我在代码中搜索了所有鼠标事件并在其中放置了断点。但该代码在出现两个错误时并未执行。
  • 使用VCLskin
  • 错误 1 出现在 Fast 报告版本 5.6.1 和 5.6.8 中。
  • Windows 10。
  • 德尔福 XE 10.2.

编辑

  • 应用程序主窗体设置正确。在启动时,首先会显示一个登录表单。登录后,创建数据模块,创建一些没有所有者的表单(它们在应用程序端被释放)。

所有其他表单,包括主表单,归应用程序所有,而不是登录表单。确实不是作为父母,而是作为所有者, 就像@uwe-raabe 所说的那样。

然后创建主窗体。这是通过登录表单创建的:

Frm_DatabaseLogin.CreateForm(TFrm_MainMenu, Frm_MainMenu);

那叫:

procedure TFrm_DataBaseLogin.CreateForm(InstanceClass: TComponentClass;
  var Reference);
begin
  Updateprogress(InstanceClass.ClassName);
  Application.CreateForm(InstanceClass,Reference);
end;

在 UpdateProgress 中没有什么特别的事情发生。

之后,其他表单也被创建,由应用程序拥有。最后,登录表单隐藏,因此显示主表单。

【问题讨论】:

  • "然后创建主窗体。它的父窗体是登录窗体。"这对我来说听起来很奇怪。你的意思是“所有者”而不是“父母”?此外,Mainform 的所有者通常是 Application,并且 Mainform 是通过调用 Application.CreateForm 在 DPR 中创建的。你能展示你的代码来创建这些表单吗?
  • 虽然这个问题可能真的很有趣,但如果没有应用程序代码,如何回答这个问题?有调试的想法?看看TWinControl.SetZOrderPositionTWinControl.WMSetFocusTCustomForm.WMActivate 吧。在例如使用断点WMSetFocus 实际上中断 可能会改变执行,因为您的应用程序和 IDE 之间发生焦点更改。对于WMSetFocusSetZOrderPosition,我会使用断点条件,例如Self is TCustomForm
  • 非常笼统的问题,背景非常具体。 “什么可能导致这些...” ...错误代码可能...在我们看不到的某个地方。

标签: windows forms delphi printing fastreport


【解决方案1】:

我在这里对你的启动代码做了一些假设。

“主要形式”可能是一个令人困惑的术语。从 TApplication 的角度来看,Application.MainForm 始终是使用 Application.CreateForm 创建的第一个表单。

由于您的登录表单创建了应用程序的主表单,然后将其自身隐藏起来,因此登录表单仍然是“主”表单。

您的屏幕截图在任务栏上显示了两个图标。我假设您正在使用或调用 CreateParams 或调用 SetWindowLong 来实现这一点。

我有一个类似的设置,然后隐藏了一个“主”登录表单。

在我的应用程序中,我为应该是独立的并具有任务栏图标的表单覆盖了 CreateParams:

procedure TMgrMain.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent := 0;
end;

然后在显示弹出窗口时,我创建了一个带有所有者的表单(可能不需要),然后设置 PopupMode 和 PopupParent。自从我开始这样做后,我不再有弹出的表单。

procedure ShowAbout(Owner: TForm);
var
  LocalForm: TAbout;
begin
  LocalForm := TAbout.Create(Owner);
  try
    LocalForm.PopupMode := pmExplicit;
    LocalForm.PopupParent := Owner;
    LocalForm.ShowModal;
  finally
    FreeAndNil(LocalForm);
  end;
end;

来自PopupParent help

如果 PopupMode 属性设置为 pmExplicit 且 PopupParent 为 nil, 然后 Application.MainForm 被隐式用作 PopupParent。 如果没有分配 Application.MainForm,则 Application.Handle 是 用作 PopupParent。

如果 PopupMode 属性设置为 pmAuto,则使用 Screen.ActiveForm 作为 PopupParent 属性。

我采取的步骤的一部分来自一位老彼得低于newsgroup post。这也是现在非常老的建议,在添加 PopupParent/PopupMode 之前

新闻组:borland.public.delphi.winapi
来自:“彼得在下面(TeamB)”
日期:2000/11/30
主题:Re:无模式窗口就像.exe

.. 切..
请注意,这可能会导致 从辅助形式显示的模态形式的一些问题。如果用户 在模态表单启动时从应用程序切换,然后返回 显示模态表单的表单可能隐藏在表单下方。它 可以通过确保模态形式来解决这个问题 显示它的表单的父级(使用上面的 params.WndParent) 但这对于对话框中的标准对话框是不可能的 单元和异常,需要更多的努力才能让它们正常工作 (基本上处理Application.OnActivate,寻找模态形式 通过 GetLastActivepopup 成为 Application 的父级并将它们带到 通过 SetWindowPos 的 Z 顺序顶部)。
.. cut ..

最后,blog post 讲述了为什么要对 PopupMode 和 PopupParent 进行更改。

【讨论】:

    猜你喜欢
    • 2010-10-15
    • 2014-10-29
    • 2010-11-03
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多