18

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" (internally 144 dpi) setting, on different systems. It seems that on some systems, that certain text/font parts of my application are being stretched and on other systems, they aren't. I would have thought that my application, on a certain version of Windows (Win7), at a certain DPI, should behave the same way.

Either my application will make it known to Windows that it doesn't need the DPI Virtualization feature, or it will not. That much I understand. What I don't understand is how DPI changes can cause different appearance on two machines, both running Windows 7, both at 144 dpi, displaying the same fonts and forms at the same fixed sizes.

Is there some configuration-dependant elements involved in DPI Virtualization that I need to inspect in windows (registry etc)? Otherwise, how do you troubleshoot and know whether DPI virtualization is being done on your client window?

In Delphi, one has to set the TForm.Scaled property to false, if one doesn't want scaling. But what I don't understand is that when the main form's Scaled property is true, I cannot always predict the outcome.

What is most perplexing to me in my application, is that I have a control that only misbehaves in my large real application, but which does not misbehave in a standalone app where I am trying to debug just the control. To understand the control behaviour in a standalone app I was forced to make a demo app where I force the DPI awareness in via the manifest file. Then I can reproduce the control drawing glitch, although in a different form.

Here is the manifest file I use in my demo app, which exposes the problems that my controls have with dealing with high-dpi settings in windows. However, one strange thing I have found is that it is possible for an application

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <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>
  <assemblyIdentity version="14.0.3615.26342" processorArchitecture="*"            
   name="TestProject" type="win32"></assemblyIdentity>
  <description>High DPI Controls Test App</description>
</assembly>

here's an example of one of about 30 places where the controls in my application are messed up when I disable DPI virtualization in my app. This particular glitch was solved by turning off the Scaled property in my form. But in other places, having TForm.Scaled=false causes the problem, whereas in some forms, it fixes it:

DPI Glitch Example with a non-DPI-virtualized app manifest, but main form is Scaled

Update: It turns out that some of my controls use GDI+ and that font behaviour in GDI+ contexts is different than font behaviour in normal GDI contexts, at least for certain third-party controls that use GDI+. That's a major source of headaches. Secondly, there is the spotty test coverage and poorly-defined requirements, for DPI awareness, in the VCL. Some VCL controls are based on MS Common Controls, and while it's fair to say that the underlying common controls probably work fine in high-DPI situations, not all the VCL control wrappers can be guaranteed to work correctly. So, reviewing an application for high-DPI-awareness in all its controls, as well as correct behaviour in all available windows 7 themes:

  1. aero glass on, at 96dpi (Default Win7 appearance on most modern hardware)
  2. basic theme (aero glass off) but xp themes enabled
  3. classic win2000 look where glass is off, as well as xp level themes,
  4. high contrast white
  5. high contrast black
  6. Various Other-than-96-DPI settings

..and the list goes on., and you have a pretty heavy burden, as an application developer. Whether you are a delphi user and use the VCL, or you are an MFC/ATL C++ developer, it seems to me, that supporting all of the various quirky windows modes is a burden almost too heavy to bear. So most people don't bother. Am I right?

4

4 に答える 4

11

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:

于 2011-02-22T15:57:26.893 に答える
9

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;
于 2011-06-24T00:44:47.387 に答える
7

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

于 2011-02-22T18:56:50.667 に答える
6

システムDPIがデフォルトの96dpi値から変更されたときのアプリケーションの癖は、次の3つの一般的なキャンプにあることがわかりました。

  1. アプリケーションのコントロールの一部はGDIを使用し、一部のコントロールはGDI+を使用します。少なくとも私が使用しているコントロールでは、GDIフォントとGDI+フォントが異なるDPIでレンダリングされる方法にいくつかの違いがあります。

  2. 私はdelphiでVCLと呼ばれるフレームワークを使用しています。このDelphiVCLフレームワークでは、一部のフォームにはTForm.Scaled = trueがあり、一部のフォームにはTForm.Scaled=falseがあります。スケーリングされた形式で各コントロールについて考える必要があるため、UIデザイナーとして、スケーリングされた形式では「醜い」または受け入れられないことが起こることがよくあります。スケールオフをオフにすると、Windows 7自体によって拡張されたフォーム、高DPI設定(DPI仮想化モード)、または小さく表示されるフォームが残ります。したがって、144 dpiバージョンの場合、必要に応じてユーザーの「要求」を無視します。 96dpiのUI。他の人は他の言語で他のフレームワークを使用しているかもしれませんし、「ダイアログユニット」でダイアログをデザインするVisualC++用のダイアログボックスエディタのような本当に古いものを使用しているかもしれません。これは、一般的なダイアログレイアウトを、ピクセルへの1:1の対応から分離しようとする別の方法です。スケーリング、ストレッチ、およびレイアウトコントロールは、UIデザインの一般的な部分であり、プラットフォームの要件に一致する方法で解決する必要があります。私の場合、VCLは、96 DPIのガラス対応エアロアプリを設計できるようにするという素晴らしい仕事をしてくれ、他のDPIレーティングでもうまく機能しますが、私のカスタムコントロールのほとんどはそうではありません。したがって、VCLに付属するコントロールを使い続けるもう1つの理由は、高DPIサポートを気にする場合、高DPIサポートを機能させようとすると作業が難しくなることです。VCLは、96 DPIのガラス対応エアロアプリを設計できるという素晴らしい仕事をしてくれ、他のDPIレーティングでもうまく機能しますが、私のカスタムコントロールのほとんどはそうではありません。したがって、VCLに付属するコントロールを使い続けるもう1つの理由は、高DPIサポートを気にする場合、高DPIサポートを機能させようとすると作業が難しくなることです。VCLは、96 DPIのガラス対応エアロアプリを設計できるという素晴らしい仕事をしてくれ、他のDPIレーティングでもうまく機能しますが、私のカスタムコントロールのほとんどはそうではありません。したがって、VCLに付属するコントロールを使い続けるもう1つの理由は、高DPIサポートを気にする場合、高DPIサポートを機能させようとすると作業が難しくなることです。

  3. 次に、DPI仮想化は、アプリケーションに明示的に含める必要のあるマニフェスト設定によって制御されます。私のアプリケーションにはすでにカスタムマニフェスト(プロジェクト設定の[Enable-windows-themes]チェックボックスをクリックしたときにDelphiアプリに含まれているものではない)が含まれているため、このDPI仮想化のオンとオフを再度切り替えてテストすることができました。どちらの場合も私のアプリケーション。アプリケーションをDPI仮想化なしで実行する準備ができていないことがわかったため、Windowsをデフォルトの動作のままにしました。他の人のアプリケーションは、100%vclコントロールを使用し、フォームスケーリングまたはその他の手法を使用して、さまざまなサイズで適切なサイズを設定する場合(DevExpressのVCL ExpressLayoutコントロールなど)、DPI仮想化を無効にして簡単に動作する可能性があります。フォントサイズ、およびDPIピッチ。)私にはそう思われる、結局のところ、VCLは十分に機能しますが、実際に産業用に強力なソリューションの場合、「高DPI環境」などの問題を適切に包括的に処理するには、VCLよりも高度なフレームワークが必要であり、サードパーティによる制御は一般的に必要です。これらの場合、現在のVCLが機能するのと同じように機能するようには設計されていません。このようなフレームワークの懸念は、WPFフレームワーク(Microsoft)およびJava(wing)で非常に明白ですが、VCLの従来の「Win16/Win32共通制御フレームワーク」の一部ではありません。これらの場合、サードパーティのコントロールは通常、現在のVCLが機能するのと同じように機能するようには設計されていません。このようなフレームワークの懸念は、WPFフレームワーク(Microsoft)およびJava(wing)で非常に明白ですが、VCLの従来の「Win16/Win32共通制御フレームワーク」の一部ではありません。これらの場合、サードパーティのコントロールは通常、現在のVCLが機能するのと同じように機能するようには設計されていません。このようなフレームワークの懸念は、WPFフレームワーク(Microsoft)およびJava(wing)で非常に明白ですが、VCLの従来の「Win16/Win32共通制御フレームワーク」の一部ではありません。

全体として、これらの変更は、Windows XPおよび他のバージョンのWindowsが「フォントサイズ」の選択を提供していた昔と比べて、今ではそれほど違いはありません(複雑です)が、現在、Windows7UIエクスペリエンスは埋めようとしていますフォントポイントサイズのオプションはかなり深く、代わりに、表面下のシステムDPIを変更する「テキストサイズ」を変更するユーザーインターフェイスを提供します。ユーザーエクスペリエンスを変更するこれらの方法はどちらも、ほとんどすべてのユーザーが、見た目がよくない、または結果として生じる変更で正しく機能しない、少なくとも1つの主要な商用アプリケーションで問題を抱えることになります。超高ドットピッチディスプレイが消費者向けPCの世界で一般的になるにつれて、この問題はますます悪化する可能性があり、より適切なフレームワークを中心としたUI設計が必要になります。

于 2011-02-24T17:30:26.000 に答える