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

后端 未结 4 1606
刺人心
刺人心 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: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;
    

提交回复
热议问题