none
dpiAware=Trueを設定したときに表示にゴミが出る RRS feed

  • 質問

  • Windows Formで、Windows7~10向けのアプリを作っています。

    高DPI対応しようと思い、以下のようなmanifestファイルをプロジェクトに追加して、dpiAware=Trueの設定をしました。

    <?xml version="1.0" encoding="utf-8"?>
    <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <asmv3:application>
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
          <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
      </asmv3:application>
    </asmv1:assembly>

    Windows10で、ディスプレイの設定でサイズを150%以上に設定すると問題ないのですが、
    125%と100%の設定では、フォームのサイズを変えた時に、下図のようにゴミ(複数の縦横の線)が出てしまい、困っています。

    なにか設定の仕方に問題等あるのでしょうか?

    高DPI対応の正しい方法等ございましたらご指導ください。


    YAMANEKO @ http://yamamaya.com/


    • 編集済み YAMAMAYA 2016年10月2日 10:48 例の画像を差し替えました
    2016年10月2日 10:19

回答

  • 私の環境(Windows 10 x64)でも下記の手順で再現しました。

    1. Windowsのディスプレイ設定で「テキスト、アプリ、その他の項目のサイズ」 = 200 % でサインイン
    2. サインインした状態でWindowsのディスプレイ設定で「テキスト、アプリ、その他の項目のサイズ」 を 100 % に変更する
    3. マニフェストで「dpiAware = true」のWindows フォームアプリを起動して、フォームのサイズを変更する


    →複数の縦横の黒い線が表示される

    100%の状態で一度サインアウトしてサインインしなおすと、再現しなくなります。
    Windows フォームの(dpiAware = true)のアプリは標準で拡大縮小の動的な変更に完全対応していないのかなと思いました。

    回避方法として、フォームのリサイズイベントに対して Invalidate() を呼び出すのはどうでしょうか?

    private void Form1_Resize(object sender, EventArgs e)
    {
        Invalidate();
    }
    • 編集済み kenjinoteMVP 2016年10月3日 9:20
    • 回答としてマーク YAMAMAYA 2016年10月3日 14:36
    2016年10月3日 8:56
  • Writing DPI-Aware Desktop and Win32 Applications - High DPI Features in Windowsで少し説明されていますが、Windows 8.1からDPI virtualization of system-DPI aware applicationsおよびPer monitor-DPI awareというものが提供されています。

    本来System-DPIの変更にはWindows 7以降ではログオフが必要です。しかしWindows 8.1以降ではSystem-DPIを変更した上でログオフするまでの間、DPI virtualization of system-DPI aware applicationsによってDPI変更を実現します。(アプリケーションはログオン時のSystem-DPI倍率で描画を行い、OSがログオン時のSystem-DPIから現在のDPIへの倍率を補正します。)

    この機能はPer monitor-DPI awareでも使用され、System-DPIとは異なる倍率に設定されているモニターに対してはOSが倍率を補正します。

    これらの場面において、質問の状況が発生するのだと思います。根本的にはSystem-DPI未対応とするか、Per monitor-DPIに対応する必要があります。

    • 回答としてマーク YAMAMAYA 2016年10月4日 6:17
    2016年10月3日 22:11

すべての返信

  • 高DPIに対応したいFormの以下の値をDpiに設定されていますでしょうか?

    https://msdn.microsoft.com/ja-jp/library/system.windows.forms.autoscalemode%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    また、以下のページにその辺について書いてありそうです。

    http://8thway.blogspot.jp/2013/09/winforms-per-monitor-dpi.html


    • 編集済み ryo1988 2016年10月3日 1:46
    2016年10月3日 1:45
  • 私の環境(Windows 10 x64)でも下記の手順で再現しました。

    1. Windowsのディスプレイ設定で「テキスト、アプリ、その他の項目のサイズ」 = 200 % でサインイン
    2. サインインした状態でWindowsのディスプレイ設定で「テキスト、アプリ、その他の項目のサイズ」 を 100 % に変更する
    3. マニフェストで「dpiAware = true」のWindows フォームアプリを起動して、フォームのサイズを変更する


    →複数の縦横の黒い線が表示される

    100%の状態で一度サインアウトしてサインインしなおすと、再現しなくなります。
    Windows フォームの(dpiAware = true)のアプリは標準で拡大縮小の動的な変更に完全対応していないのかなと思いました。

    回避方法として、フォームのリサイズイベントに対して Invalidate() を呼び出すのはどうでしょうか?

    private void Form1_Resize(object sender, EventArgs e)
    {
        Invalidate();
    }
    • 編集済み kenjinoteMVP 2016年10月3日 9:20
    • 回答としてマーク YAMAMAYA 2016年10月3日 14:36
    2016年10月3日 8:56
  • 有難うございます。

    DPIに設定してあります。Fontも試してみましたが違いは特にないようでした。


    YAMANEKO @ http://yamamaya.com/

    2016年10月3日 14:22
  • 有難うございます!

    確認できました。確かに、一旦サインアウトすると再現しなくなりました。
    アプリを再起動すれば大丈夫だと思っていましたが、OS側でもなにか、サインアウトしないと初期化されない何かがあるようですね。。

    OSの仕様として、解像度変更後はサインアウト推奨なら仕方ないので、
    とりあえず、Resize時にInvalidateで再描画させてみて、それでも何か不具合あるようなら、サインアウトしなおすのを前提にしようと思います。


    YAMANEKO @ http://yamamaya.com/

    2016年10月3日 14:35
  • Writing DPI-Aware Desktop and Win32 Applications - High DPI Features in Windowsで少し説明されていますが、Windows 8.1からDPI virtualization of system-DPI aware applicationsおよびPer monitor-DPI awareというものが提供されています。

    本来System-DPIの変更にはWindows 7以降ではログオフが必要です。しかしWindows 8.1以降ではSystem-DPIを変更した上でログオフするまでの間、DPI virtualization of system-DPI aware applicationsによってDPI変更を実現します。(アプリケーションはログオン時のSystem-DPI倍率で描画を行い、OSがログオン時のSystem-DPIから現在のDPIへの倍率を補正します。)

    この機能はPer monitor-DPI awareでも使用され、System-DPIとは異なる倍率に設定されているモニターに対してはOSが倍率を補正します。

    これらの場面において、質問の状況が発生するのだと思います。根本的にはSystem-DPI未対応とするか、Per monitor-DPIに対応する必要があります。

    • 回答としてマーク YAMAMAYA 2016年10月4日 6:17
    2016年10月3日 22:11
  • 丁寧な解説ありがとうございます。

    なるほど、それで、解像度を変更してからログオフするまでは、微妙に文字がにじんだり、こういったゴミが出るような現象が起きるのですね。(ゴミが出るのはやはり不具合ではないかと思いますが・・・)

    System-DPIを使わずに対応するのも大変そうなので、とりあえず、ウィンドウリサイズ後にInvalidateして再描画させる方針で行こうと思います。


    YAMANEKO @ http://yamamaya.com/

    2016年10月4日 6:17