如何使悬停在最小化、最大化和关闭按钮上的行为正常?

How to make hovering over Minimize, Maximize, and Close buttons behave?

在 Delphi 应用程序中,当您将鼠标悬停在边框图标上时,例如:

它的行为不正确:

与行为正确的应用程序比较:

复制步骤

  1. 单击 文件新建VCL 表单应用程序 - Delphi
  2. 单击运行 (F9)
  3. 将鼠标悬停在最小化、最大化或关闭按钮上。

如何修复?

Edit - 它也因 Delphi 7:

而失败

并在 Delphi 5:

并在 Delphi 4:

我假设(即害怕)它是由 ThemeServices 引擎引起的;他们可能认为不尊重用户的偏好很酷。但看起来它是更基本的东西。

兼容模式

Skype

在 Skype 中也失败;也写在Delphi:

高 DPI 是诱因

我终于弄明白为什么它在我用过的每 Windows 10 台机器上都失败了;但不适合所有人。高 dpi.

将您的 dpi 设置为 97 (101%) 或更高。

足够接近

Dalija 的解决方案有效:

我们将忽略工具提示的问题,改天再战。

还应注意,Windows 10 会提示您可能需要注销并重新登录才能使某些应用程序在更改 DPI 后正常工作。 Delphi.

确实如此

还需要注意的是,Delphi 不能容忍 DPI 像这样在背后改变。这包括调整 缩放 滑块。这还包括将应用程序放置在除主显示器之外的任何显示器上。

而且我们从来没有弄清楚问题是什么;只为用户 运行 多个显示器踢了它。

QC 错误报告

因为 Bor...Impr...CodeG...Embarca... Idera 的 QC 站点在 pay-wall 后面,这里是 bug report:

如您所见:没人关心。

高 DPI 是导火索,也是解决之道。

出现问题的应用程序不支持高 DPI。悬停问题的解决方法是使用1、2或3下的解决方案之一让他们知道或打开关联的兼容模式。

注意:当启用高 DPI 感知时,应用程序的其余部分是否会正常运行是另一个问题,并且会因应用程序而异。

  1. 兼容模式下检查"Disable display scaling on high DPI settings"

  2. 调用 SetProcessDPIAware 作为 .dpr 文件中的第一个调用 - 如 Ian Boyd 所述,调用此函数可能导致竞争条件,首选方法是使用清单。 SetProcessDPIAware

  3. 使用具有 truetrue/PM 设置的自定义清单("Enable runtime themes" 中包含的默认 Delphi 清单不支持高 DPI)

当前版本的 Delphi VCL 和 FMX 框架缺乏对每个监视器 DPI 感知的支持,因此仅当您自己处理每个监视器 DPI 时才使用 true/PM 清单。向 QP 报告为 VCL and FireMonkey lack Per-Monitor DPI support for Windows 8.1 (and Windows 10)


  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>

  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true/PM</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>

更新:

Delphi VCL 是错误行为的根源,具体问题出在 TForm class 或其祖先中的某处。当直接使用 Windows API 时,结果 windows 表现正常。

Windows API 行为正常的代码:

  MessageBox(0, 'Correct', 'Caption', MB_OK); 

  ShowMessage('Correct'); // if themes are enabled -> Windows Task dialog is used

完整的 Delphi 示例应用程序,它在不使用 VCL 的情况下创建主要 window - 行为正常

program win;

{$R *.res}

uses
  Windows,
  Messages,
  SysUtils;

var
  Msg: TMSG;
  LWndClass: TWndClass;
  hMainHandle: HWND;

function WindowProc(HWND, Msg: Longint; wParam: wParam; lParam: lParam): Longint; stdcall;
begin
  if Msg = WM_DESTROY then PostQuitMessage(0);
  Result := DefWindowProc(HWND, Msg, wParam, lParam);
end;

begin
  LWndClass.hInstance := hInstance;
  with LWndClass do
    begin
      lpszClassName := 'WinApiWnd';
      Style := CS_PARENTDC or CS_BYTEALIGNCLIENT;
      hIcon := LoadIcon(hInstance, 'MAINICON');
      lpfnWndProc := @WindowProc;
      hbrBackground := COLOR_BTNFACE + 1;
      hCursor := LoadCursor(0, IDC_ARROW);
    end;

  RegisterClass(LWndClass);
  hMainHandle := CreateWindow(LWndClass.lpszClassName, 'Window Title', WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU or WS_VISIBLE, 0, 0, 360, 200, 0, 0, hInstance, nil);

  while GetMessage(Msg, 0, 0, 0) do
    begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
end.

行为不当的 VCL 表单:

var
  f: TForm;

  f := CreateMessageDialog('Broken', mtWarning, mbOKCancel, mbOk);
  f.ShowModal;
  f.Free;

  f := TForm.Create(nil);
  f.ShowModal;
  f.Free;