Written in Japanese(UTF-8)
2021. 4. 7
INASOFT

/トップ/目次/管理人のひとこと/C++で作成するWindowsフォームアプリケーションでも高DPI環境に労力かけずに対応したいメモ

2560903 (+0050)[+0708]

管理人のふたこと

C++で作成するWindowsフォームアプリケーションでも高DPI環境に労力かけずに対応したいメモ



公開日:2021/04/06
公開日:2021/04/07 マウスのお供のダイアログに一工夫
公開日:2021/04/07 最近のWindowsではモニタごとに拡大率を変えられる

だいぶ前のことになりますが、設定ダイアログをなるべく楽に拡大したい話を書いたときに、Windowsによる自動的な(※)拡大について書きました。

  (※)ここでいう「自動的な」というのは、プログラマの手を煩わせない、というか、プログラマがプログラムせずとも、OSが勝手にやってくれちゃうような物事のことを指します。

ダイアログの自動的な拡大は、Windows自身の画面の拡大率の設定で発生します。いわゆる「高DPI(Hi-DPI)環境」というやつです。DPIは、Dot per Inchの略です。

Windowsの標準的な画面サイズは、92dpiであり、この数字が大きくなっていけば、「画面が大きくなった」(画面の大きさに対し、内容物のサイズ(文字など)が大きくなった)状態となります。

下記の図は、以前の記事でご紹介した「ディスプレイ設定によるアプリケーションのウィンドウのサイズを中身ごと変える方法」の図となります。
Windows 10では「拡大縮小とレイアウト」という名前の設定で、100%~175%の選択肢の中から選ぶようになっています。

ディスプレイ設定によるアプリケーションのウィンドウのサイズを中身ごと変える方法1 ディスプレイ設定によるアプリケーションのウィンドウのサイズを中身ごと変える方法2

Windows 10でこの設定を行うと、例えば「マウスのお供」のプロパティーシートの1ページ目であれば、次のような拡大が起こります。

標準サイズ:
マウスのお供の設定ダイアログ(プロパティシート1ページ目)

拡大サイズ:
OSの設定で無理やり引き延ばされた「マウスのお供」の設定ダイアログ(プロパティシート1ページ目)ギザギザ版

なんだか、ギザギザというか、モヤモヤというか、そんな感じのサイズです。(Windows 10の多くの「設定」アプリのような、WPFを用いて作成されているアプリケーションの場合は、きれいに拡大されます→2019年11月の記事参照)

ちなみに、Windows XPまでは、フォントの大きさが変えられた状態でダイアログ上のコントロールの描画が行われていました。Windows 10でこれと同じことを再現するには、exeファイルのプロパティの「互換性」設定の「高DPI設定の変更」で「高DPIスケール設定の上書き」から「アプリケーション」を選びます。

互換性設定を有効にする方法 互換性設定で無理やり引き延ばされた「マウスのお供」の設定ダイアログ(プロパティシート1ページ目)
▲OSの設定で無理やり引き延ばされた「マウスのお供」の設定ダイアログ(プロパティシート1ページ目)なめらか版



この方が、最初に示したギザギザ・モヤモヤなダイアログよりもきれいなのですが、ダイアログ内のテキストの右側の方が欠けてしまうことがわかると思います。テキストボックス(入力欄)内部のテキストの縦位置も微妙。この問題は、拡大率を上げれば上げるほど顕著になります。

Windows XPまでは、こちらが標準的な自動拡大方法でした。これは想像ですが、画面を拡大するとダイアログ上のテキストの右側が欠けてしまう現象について、マイクロソフト社にクレームが多く寄せられたのかもしれません。そのため、ギザギザ・モヤモヤなダイアログは気持ち悪いけれど、文字が書けてしまうよりはマシ。少なくとも、実務上の問題は発生しないから、という判断が行われたのかもしれません。


ところで、Windows 10の比較的最近のバージョンでは、ダイアログ内のテキストの右側の方が欠けないような自動拡大の方法が実装されたそうです。「システム(拡張)」というものです。

互換性設定を「システム(拡張)」にする

互換性設定で自動拡大された「マウスのお供」の設定ダイアログ(プロパティシート1ページ目)

うーむ、文字の右端が欠けてしまった……。

ちなみに、「マウスのお供」以外のアプリケーションで試したところ、欠けないことの方が多かったので、満を持して「マウスのお供」に適用してみたのですが、ダイアログ内に要素がギチギチに詰まっているようだとダメみたいですね。

なお、exeファイルの「プロパティ」の「互換性」設定を使わずにこの機能を利用するには、アプリケーションのマニフェストに次のように記述します。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   :
   :
   :
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
        <gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling>
    </windowsSettings>
  </application>
</assembly>

ちなみに、「マウスふるふる」と「NumLockLock」の2つのアプリケーションの設定ダイアログでは、なんだかイイ感じに拡大されてくれましたので、この2つのアプリケーションでは採用の方向で考えたいと思います。

互換性設定で自動拡大された「マウスふるふる」の設定ダイアログ
▲互換性設定で自動拡大された「マウスふるふる」の設定ダイアログ(正式採用する際には、manifestに記述しておきますので、互換性設定をする必要はありません)

互換性設定で自動拡大された「NumLockLock」の設定ダイアログ
▲互換性設定で自動拡大された「NumLockLock」の設定ダイアログ(正式採用する際には、manifestに記述しておきますので、互換性設定をする必要はありません)



マウスのお供のダイアログに一工夫

上記でうまく行かなかった「マウスのお供」のプロパティシート1ページ目については、横幅を少し拡大(論理サイズ:303)し、少しだけ余裕を持った配置とすることで、どうやら解決しました。

拡大前のダイアログ
▲拡大前の「マウスのお供」プロパティシート1ページ目



画面のサイズを125%とし、自動拡大されたダイアログ
▲画面のサイズを125%とし、自動拡大された「マウスのお供」プロパティシート1ページ目



最近のWindowsではモニタごとに拡大率を変えられる

ところで、最近の(?)Windowsでは、モニタごとに拡大率を変えられる仕組みがあったりします。

PCに複数のモニタを繋ぐことは、普通にできるようになってきており、私自身も自宅・仕事場共に2台のモニタが使えるようにしてあります。私の知人で3台のモニタで作業をしている人もおり、あるプログラマを主人公とした小説では「作業効率はモニタの台数に比例する」とまで言い切っていたのが印象的でした。

複数のモニタの接続とはいっても、様々な形態があり、すべてを作業用として使うこともあれば、サブモニタをスライド発表用として、投影機、あるいは、巨大スクリーンに接続する場合もあり得ます。

このように、サブモニタを極端に大きなスクリーンとする場合、拡大率の設定もモニタごとに変えたくなるわけで、Windowsはそのような仕組みにも対応しています。問題は、OSがそのような仕組みに対応していたとしても、各アプリケーションがその仕組みに対応できるか?です。

モニタの拡大率について解説しているプログラミング系の記事では「Per Monitor」と呼んでいるものです。

ちなみに、巨大なスクリーンをモニタとして接続すると、Windowsは自動的に、というか勝手に、100%より大きい拡大率を設定するようです。

これまでの例に挙げた通り、各アプリケーションの作者は、どのモニタに映っているかで、ダイアログのサイズやコントロール位置などの各要素の座標値・サイズ値がコロコロ変わるような前提でモノ作りしていなかったりしますし、ましてやそれがインタラクティブに変わる想定などしていないです。

ちなみに、「マウスふるふる」の設定ダイアログを、拡大率の異なるモニタ間で移動させると、こんな挙動になります。


▲「マウスふるふる」設定ダイアログふるふる

まぁとりあえず、サイズがコロコロ変わろうとも動いてくれているようなのでこのままにしたいと思いますが、もしかしたら何らかの不具合が見えないところで生じている可能性もあり、そのあたりは、見つかり次第、順次対応していきたいと思います。

このほかに、マルチモニタを前提とした環境の場合、マイナス値の座標が現れるという問題があります。普通にWindowsのプログラムを作っているのなら気にならないのですが、アプリケーション終了直前の座標を保存しておく仕組みを構築する場合に、暗黙のうちに負の座標を排除するようなプログラミングをしていないか?みたいなことがあったりします。プライマリモニタの左上が(0,0)になることから、セカンダリモニタをプライマリモニタの表示位置より左または上に配置したならば、マイナスの座標が平然と現れるのですが、こういうのは、そういう環境を持っていて、実際にテストしないと、明らかにならないバグに繋がったりします。

20年くらい前に、あるソフトウェアがマルチモニタに起因する問題を抱えていた時、公開元サイトの掲示板に書き込まれたバグ報告に対し、「マルチモニタ環境は一般的ではなく、当方もそういった環境は持っておらず、テストもできないから、対応もしない」と言い切っていたのを見たことがありました。20年前ならそれで許されていたのかもしれませんが、さすがに現在では、そう切って捨てるのも難しいです。

物理的にそういった環境を準備できずとも、VirtualBoxを無償で入手できて、Windowsのテスト環境イメージを無償で入手できて、VirtualBoxではディスプレイ数を2以上にするエミュレーションもできてしまいますからね。

あとは時間モチベさえ確保できれば、テストできてしまいます。20年前と比べたら、フリーソフト開発のテスト環境は、格段によくなりました。




本ページへは、自己責任の範囲内であれば自由にリンクしていただいて構いません。
本ページに掲載されている内容は、自由にお使いいただいて構いませんが、必ずしも筆者が内容を保証するものではありませんので、ご利用に際しては自己の責任においてお使いいただきますよう、お願いいたします。
このページのURLやアンカーは、サーバ運営・サイト運営・ページ運営・その他の都合により無告知で一時的あるいは永遠に消滅したり、変更したりする可能性がありますので、あらかじめご了承下さい。
本ページは、公開から1年半経過後の任意のタイミングで削除される予定です。本ページの内容は複製・公開していただいて構いません。


/トップ/目次/管理人のひとこと/C++で作成するWindowsフォームアプリケーションでも高DPI環境に労力かけずに対応したいメモ