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

后端 未结 1 924
无人及你
无人及你 2020-12-15 05:32

In a Delphi application, when you hover over a border icon, e.g.:

  • Minimize
  • Maximize
  • Restore

it doesn\'t behave correctly:

相关标签:
1条回答
  • 2020-12-15 06:10

    High DPI is the trigger and it leads to the solution.

    Applications that exhibit the issue are not High DPI aware. Solution to hovering problem is to make them aware or turn on associated compatibility mode by using one of solutions under 1, 2 or 3.

    Note: whether will rest of the application behave properly when High DPI awareness is turned on is another issue and will differ from application to application.

    1. Under compatibility mode check "Disable display scaling on high DPI settings"

    2. Call SetProcessDPIAware as first call in .dpr file - as noted by Ian Boyd, calling this function can leat to race condition and preferred way is using manifest. SetProcessDPIAware

    3. Use custom manifest with true or true/PM setting (default Delphi manifest included with "Enable runtime themes" is not high DPI aware)

    Current versions of Delphi VCL and FMX frameworks lack support for per monitor DPI awareness, so use true/PM manifest only if you are handling per monitor DPI yourself. Reported to QP as 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>
    

    or

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

    Update:

    Delphi VCL is source of buggy behavior, specifically issue is somewhere in TForm class or its ancestors. When direct Windows API is used resulting windows behave normally.

    Windows API code that behaves properly:

      MessageBox(0, 'Correct', 'Caption', MB_OK); 
    
      ShowMessage('Correct'); // if themes are enabled -> Windows Task dialog is used
    

    Full Delphi sample app that creates main window without using VCL - behaves properly

    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.
    

    Misbehaved VCL forms:

    var
      f: TForm;
    
      f := CreateMessageDialog('Broken', mtWarning, mbOKCancel, mbOk);
      f.ShowModal;
      f.Free;
    
      f := TForm.Create(nil);
      f.ShowModal;
      f.Free;
    
    0 讨论(0)
提交回复
热议问题