delphi - 模态窗口后面的网格滚动

标签 delphi windows-10 delphi-xe3

我已经构建了这个问题的 MCV,并且很高兴上传它。我会先尝试描述问题。

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

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

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

请仔细按照这些步骤来重现问题。

  1. 运行应用程序。

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

  3. 按下该按钮可启动非模式窗口。

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

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

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

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

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

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

最佳答案

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

但是,无需特殊要求即可演示该问题。这将是比问题中更简单的再现。

在表单上放置一个 stringgrid 和一个按钮,该按钮的点击处理程序中包含以下代码:

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;

关于delphi - 模态窗口后面的网格滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37328375/

相关文章:

delphi - Delphi标签地址

delphi - 如何增加 FOR 循环语句中的 FOR 循环值?

r - 设置工作目录: "Error in setwd: cannot change working directory" under "C:/Documents and Settings/..."

delphi - 使用初始化部分进行模块注册是个好主意吗?

rest - Delphi XE3 - datasnap REST 服务器 UTF8 输出

delphi - 在 delphi TForm 类中仅出现 'public' 错误

delphi - 将纹理指定给 TModel3D

delphi - 如何在 C++Builder 项目中静态链接 Delphi 过程

c# - 已启用的组合框控件在 Windows 10 中看起来已禁用?

php - 在 Windows 10 上安装 Apache 2.4 和 PHP 7