4K時代のWindows Forms:ぼやけを排除し、ピクセルパーフェクトを実現する「Per-Monitor V2」の深淵
かつて、VB.NETによるWindows Formsアプリケーションは「手軽にUIを構築できる」という甘美な代名詞だった。しかし、4Kディスプレイが標準となった現代において、その「手軽さ」は「負の遺産」へと変貌する。DPI(Dots Per Inch)スケーリングを考慮しない設計は、文字を滲ませ、レイアウトを崩壊させ、ユーザーの生産性を著しく低下させる。
もはや「Windowsが勝手に拡大してくれる」という幻想を捨てるべきだ。今、我々アーキテクトが向き合うべきは、OSの拡大縮小機能に依存しない、堅牢なUIの再定義である。
—
1. マニフェスト設定の「聖域」を守る
まず、アプリケーションをDPI非対応の「レガシーな箱」から解き放たねばならない。`app.manifest`の編集は、全ての始まりだ。ここで`dpiAwareness`を適切に設定しなければ、どれほど高尚なロジックを組もうとも、Windowsはアプリをビットマップとして引き延ばし、無惨なぼやけを演出する。
ここで重要なのは `PerMonitorV2` の指定だ。これは、モニターごとにDPIが異なるマルチディスプレイ環境において、ウィンドウが移動するたびに動的な再描画をOSへ要求するフラグである。
—
2. フォームの「自動スケーリング」を制御せよ
デフォルトの `AutoScaleMode = Font` は、開発環境のフォント設定に強く依存する。これを安易に信じてはならない。現場の過酷な環境(ノートPC単体、外部4Kモニタへの接続、リモートデスクトップ経由)を渡り歩くアプリであれば、レイアウトの計算式をより厳密に管理する必要がある。
特に、`TableLayoutPanel` や `FlowLayoutPanel` を駆使し、絶対座標(`Location`プロパティのベタ打ち)を排除することこそが、崩壊を防ぐ唯一の解である。
—
3. DPI変化を検知する:Windows APIの介入
`PerMonitorV2` を有効にしても、OSが全てのコントロールを完璧に再計算してくれるとは限らない。特に古いActiveXコントロールや、独自描画を行っているカスタムコンポーネントは、DPIの変更通知を拾い損ねる。
伝説的なエンジニアは、OSが発する `WM_DPICHANGED` をフックし、自ら再描画のトリガーを引くことを厭わない。
.net
‘ Windows APIの呼び出しによるDPI検知の実践
Protected Overrides Sub WndProc(ByRef m As Message)
Const WM_DPICHANGED As Integer = &H2E0
‘ DPIが変更された瞬間にレイアウトを強制再計算する
If m.Msg = WM_DPICHANGED Then
‘ 新しいDPI値を取得し、フォームのスケールを再適用
Dim newDpi As Integer = m.WParam.ToInt32() And &HFFFF
Me.PerformAutoScale()
End If
MyBase.WndProc(m)
End Sub
—
4. オブジェクトのライフサイクルとメモリ最適化
高DPI対応で忘れがちなのが、再描画に伴う「リソースのリーク」だ。特にGDI+オブジェクト(`Pen`, `Brush`, `Bitmap`)をDPIが変わるたびに再生成する場合、`Dispose()`を明示的に呼び出さなければ、メモリは雪だるま式に肥大化する。
- 鉄則: `Using` ブロックを活用せよ。
- 鉄則: 大規模な画像リソースはキャッシュし、DPI変更時のみ破棄・再生成のロジックを通せ。
.net
‘ 不適切なリソース解放の例(メモリリークの温床)
‘ Dim g As Graphics = Me.CreateGraphics()
‘ Dim p As New Pen(Color.Red) … これを繰り返すと確実に落ちる
‘ 正しい実装:Usingでスコープを限定し、明示的破棄を保証する
Using g As Graphics = Me.CreateGraphics()
Using p As New Pen(Color.Red)
g.DrawLine(p, 0, 0, 100, 100)
End Using
End Using
—
結論:レガシーを「モダン」として延命させるために
Windows Formsは死んでいない。しかし、何も考えずに動かしているだけのアプリは、現代のディスプレイ環境では「死んでいる」も同然だ。
1. マニフェストで `PerMonitorV2` を宣言する。
2. 絶対座標を捨て、レイアウトコンテナ(TableLayoutPanel等)に全権を委ねる。
3. DPI変更イベントを監視し、必要ならば強制再描画を行う。
4. GDI+のリソース管理を、GC(ガベージコレクター)任せにしない。
これらを実行するだけで、貴方の開発するシステムは、次の10年も現役として戦えるだけの「美しさ」と「頑健さ」を手に入れる。技術に対する敬意を忘れず、細部にこそ神を宿せ。それが、我々エンジニアの矜持である。
