Troubleshooting DPI Virtualization and DPI-aware applications, in Windows Vista and Windows 7

后端 未结 4 1607
刺人心
刺人心 2021-01-30 14:47

I have a problem where an application (written in Delphi) is behaving properly at default 96 DPI settings on all systems, but is behaving inconsistently at the \"150% text size\

相关标签:
4条回答
  • 2021-01-30 15:18

    enter image description hereThe "Custom DPI Setting" window has a "Use Windows XP style DPI scaling". That might explain the different behaviour.

    0 讨论(0)
  • 2021-01-30 15:25

    It turns out that the quirks in my Application when the system DPI changed away from the default 96 dpi value, are in three general camps:

    1. Some of the application's controls use GDI and some controls use GDI+. There are some differences in how a GDI and GDI+ font renders at different DPI, at least in the controls I am using.

    2. I use a framework called VCL in delphi. In this Delphi VCL framework, some forms have TForm.Scaled=true, and some have TForm.Scaled=false. Because it requires you to think about each control in a scaled form, it is very common to have things happen that you as a UI designer will find "ugly" or unacceptable in a Scaled form. Turning Scaled off, you are left with forms that are either stretched by Windows 7 itself, in high DPI settings (DPI Virtualization mode) or which appear small and therefore, ignore the user's "request" if you like, for a 144 dpi version of your 96 dpi UI. Other people might be using other framworks in other languages, or might even be using something really old fashioned, like the Dialog Box Editor for Visual C++, where you design dialogs in "Dialog Units", which is another way of trying to separate general dialog layout, from a 1:1 correspondence to pixels. Scaling, stretching, and layout controls are a general part of UI design that must be solved in a way that matches platform requirements. In my case, the VCL does a great job of letting me design a 96 DPI glass-enabled aero app, and works great at other DPI ratings, but most of my custom controls don't. So it's another reason to stick with the controls that come with the VCL: If you care about high DPI support, your job gets harder when you try to make high DPI support work.

    3. DPI Virtualization in turn, is controlled by a manifest setting that you must expressly include in your application. Since my application already had a custom manifest (not the one that is included with your Delphi app when you click the Enable-windows-themes checkbox in the project settings), I was able to turn this DPI virtualization on and off again, and test my application in both cases. I found that my application was not ready to run without DPI Virtualization, and thus I left Windows to its default behaviour. Other people's applications might easily work with DPI Virtualization disabled, if they use 100% vcl controls, with forms that either use Form scaling, or some other technique, to appropriately size themselves (such as the VCL ExpressLayout control from DevExpress) at a variety of font sizes, and DPI pitches.). It seems to me, that in the end, the VCL is functional enough, but that for really industrial-strength solutions, a more advanced framework than the VCL is required, to comprehensively deal with issues like "high DPI environments" properly, and that third party controls are generally not designed to work even as well as the current VCL works, in these cases. Such framework concerns are very much in evidence in the WPF framework (Microsoft) and in Java (wing), but are not part of the classic "Win16/Win32 common control framework" of the VCL.

    All in all, these changes are not that different (complex) now, than in the old days, when Windows XP and other versions of Windows offered you a choice of "font sizes", whereas now, the Windows 7 UI experience tries to bury the font point size options pretty deeply, and instead offers you a "text size" changing user interface that modifies the system DPI below the surface. Both of these ways of changing your user experience result in almost every user having problems with at least one major commercial application that doesn't look, or work correctly with the resulting changes. As ultra-high dot-pitch displays become more common in the consumer PC landscape, this problem will probably get worse and worse, and UI design around more suitable frameworks will be required.

    0 讨论(0)
  • 2021-01-30 15:33

    It's actually a different question than that.

    Your forms should not be getting larger with the user's DPI, they should be getting larger with font size.

    Delphi's default form font is 8pt Tahoma.
    The average 8pt Tahoma character is: 6.08px * 13px.

    Starting with Windows Vista, the default font is 9pt Segoe UI.
    The average 9pt Segoe UI character is: 6.81px * 15px.

    enter image description here

    Your Windows applications should be honoring the user's font preference (i.e. IconTitleFont).

    My Windows font preference is 12pt Segoe UI, whose average character size is: 8.98px * 21px:

    enter image description here

    This means that if you designed your form at Tahoma 8pt (13px high), you need to scale the form, and all the child controls, by 162%:

    scaleFactor = (userFontSize / designedFontSize)
                = 21px / 13px
                = 1.615
    

    If you're careful you'll notice that changing DPI is just a special case of changing the font size. Your 8pt font is still 8pt, but 8pt translates into more pixels. If you run 131dpi (136% zoom setting in Windows 7) then:

    9pt Segoe UI,  96dpi = 6.81px x 15px
    9pt Segoe UI, 131dpi = 8.98px x 21px
    

    enter image description here

    Note: It's not a coincidence that i chose 131dpi and 12pt as my examples. At work i run 96dpi but 12pt. At home i run 9pt but 131dpi. Both have the same pixel font height, 21px.


    In the end you need to call ScaleControl by the size difference:

    procedure StandardizeFormFont(Form: TForm);    
    var
       iconTitleFontName: string;
       iconTitleFontSizePixels: Integer;
       currentFontSizePixels: Integer;
    begin
       GetIconTitleFont(iconTitleFontName, iconTitleFontSizePixels);
    
       //Change font face first
       //Some fonts are inheriently taller than others
       //(even at the same point size)
       Form.Font.Name := iconTitleFontName;     
    
       //Get the form's current font height (in pixels)
       currentFontSizePixels := Form.Font.Height; //negative number, but so is iconTitleFontSizePixels
    
       Form.ScaleBy(iconTitleFontSizePixels, currentFontSizePixels);
    end;
    

    In reality this code is very simplistic. Many child controls need to be updated manually:

    • listview columns need to get wider
    • controls with ParentFont = false need to have their font's adjusted
    • TImage controls need to stretch their image to the new size
    • toolbar's need to use larger images

    In reality we use a super-fancy version of StandardizeFormFont that recursively goes through all controls on the form and does it's best to adjust each control based on what it is.

    Every control is Delphi is supposed to override it's ScaleControl method, and make the adjustments it needs to:

    protected
       procedure ChangeScale(M, D: Integer); override;
    
    0 讨论(0)
  • 2021-01-30 15:36

    You need to manifest that your app is DPI aware with a section like this:

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

    If you do this then you won't get DPI virtualization.

    You aren't meant to use DPI virtualization so I think there's little point trying to work out how it works. It could easily be dependent on graphics card drivers. It's almost impossible for us to explain why virtualization is behaving this way: you haven't even given any screenshots, hardware details etc. However, you simply shouldn't bother trying to diagnose this. Manifest as dpiaware and it's a non-problem.

    For reference I offer you:

    • Writing High-DPI Win32 Applications
    • http://www.rw-designer.com/DPI-aware
    0 讨论(0)
提交回复
热议问题