【问题标题】:Grid Scroll Behind Modal Window模式窗口后面的网格滚动
【发布时间】:2016-05-19 15:53:56
【问题描述】:

我已经为这个问题建立了一个 MCV,我很高兴上传它。我会先尝试描述问题。

  1. 创建一个主窗口并放置一个通过任何可用数据库连接到表的 TDBGrid。窗口的 OnShow 连接到数据库并打开表。

  2. 在主窗口上创建一个按钮以启动非模态窗口。

  3. 在非模态窗口上创建一个启动模态窗口的按钮。

仔细按照这些步骤复制问题。

  1. 运行应用程序。

  2. 将焦点放在网格中并使用鼠标滚轮上下滚动。

  3. 按下按钮启动非模态窗口。

  4. 当非模态窗口打开时,单击回到主窗口中的网格,然后再次使用鼠标滚轮上下滚动。

  5. 当仍聚焦在网格中时,单击非模态窗口上的按钮以启动模态窗口。

  6. 当模式窗口打开时,将鼠标悬停在网格上并使用鼠标滚轮。您会看到网格上下滚动。

这不会在 Windows 7 上发生,但在 Windows 10 上会发生。它可能看起来无害,但当您在 ​​3 个窗口中构建了几层父子关系时,它尤其危险。

假设模态窗口包含主窗口的孙子。如果用户启动模态窗口的目的是编辑特定的孙子,并且不小心使用了鼠标滚轮并在主窗口上移动了祖父,那么他们现在正在编辑他们不打算的孙子。

需要注意的是,在第 4 步和第 5 步之间,如果在启动模态窗口之前没有将焦点放在网格中,则不会出现此问题。在显示模态窗口之前,我尝试以编程方式将焦点设置到非模态窗口上的控件中,但没有成功。

【问题讨论】:

  • 显示模态窗口时主窗口是否正确禁用?
  • 确实如此。 AAMOF 我可以用 W7 上的字符串网格复制它。
  • 它似乎依赖于鼠标驱动程序/软件设置而不是操作系统。如果我在我的盒子上禁用“wizmouse”,它就不会发生。
  • 不客气。但是,您仍然有问题。禁用的窗口不应滚动。
  • @sertac 这是 vcl 网格的问题。列表框是否滚动?

标签: delphi windows-10 delphi-xe3


【解决方案1】:

这是 VCL 代码中的错误。要在普通应用程序中重现该问题,如 cmets 所述,需要启用 Windows 10 的非活动窗口滚动功能,或在早期操作系统中提供类似功能的软件。

但是,可以在没有特殊要求的情况下演示该问题。这将比问题中的更简单。

在表单上放置一个字符串网格和一个按钮,该按钮在其点击处理程序中具有以下代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
  StringGrid1.Enabled := False;
  SetFocusedControl(StringGrid1);
end;

单击按钮并将鼠标悬停在网格上并滚动。被禁用后,网格不应该滚动,但它会滚动。

下面是对问题中案例的更合适的问题再现。这是因为模态窗口禁用了包含网格的表单,然后发布鼠标滚轮消息。车轮消息是为没有上述要求的环境合成的。

procedure TForm1.Button1Click(Sender: TObject);
var
  Pt: TPoint;
begin
  Enabled := False;
  Pt := Point(1, 1);
  MapWindowPoints(StringGrid1.Handle, HWND_DESKTOP, Pt, 1);
  SetFocusedControl(StringGrid1);
  Perform(WM_MOUSEWHEEL, MakeWParam(0, WORD(-120)), MakeLParam(Pt.X, Pt.Y));
end;

观察到网格滚动后按 Ctrl+F2。


问题的根本原因是,VCL 不关心控件是否启用,同时决定它是否是焦点控件,并使其执行鼠标滚轮消息。将鼠标滚轮消息更改为 CM_MOUSEWHEEL 并完全绕过默认窗口过程,VCL 应该已经执行了这些检查。

作为一种解决方法,您可以在启动模态表单之前将焦点控件设置为不同的控件:

MainForm.SetFocusedControl(MainForm);
OtherForm.ShowModal;

您不能在此处设置ActiveControl,因为它具有必要的可见性/状态检查。

如果不想和主窗体耦合,可以在主窗体上放一个鼠标滚轮消息处理函数:

type
  TMainForm = class(TForm)
    ...
  protected
    procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;

...

procedure TMainForm.WMMouseWheel(var Message: TWMMouseWheel);
begin
  if IsWindowEnabled(Handle) then
    inherited;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多