Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi】高DPIの有効化設定と個別スケーリング手順

高DPIの有効化設定

Delphi/400 10 Seattle以降では、
プロジェクトオプションで高DPIの有効化がサポートされています。

高DPIを有効にすると、Windowsのディスプレイの設定における
拡大縮小の設定(テキスト、アプリ、その他の項目のサイズを変更する)に対応します。
ディスプレイの拡大縮小が100%でない場合に、フォームやその中の項目のサイズが自動拡張されます。

 
それぞれ、以下の設定で有効化が可能です。

  • 10 Seattle / 10.2 Tokyo
    • アプリケーション → マニフェストファイル → 「高 DPI の有効化」をチェックオン
      (デフォルトは有効になっています)
       
  • 11 Alexandria / 12 Athens
    • アプリケーション → マニフェスト → 「DPI の認識」の各項目値を設定
    • 各項目の設定値について:
      • [なし]: DPI 認識なし。
      • [対応せず]: 100%スケーリング(96 DPI)を想定してアプリケーションをレンダリングします。
      • [システム DPI に対応]: PCログイン時にメイン ディスプレイのアプリケーション API が分かっている場合に選択します。
      • [ディスプレイごとの DPI に対応]: アプリケーションが異なる DPI を持つモニター間を移動する際に、随時 DPI スケーリングを変更させる場合に選択します。
      • [ディスプレイごとの DPI に対応 V2]: 初期値。アプリケーション DPI が変わる際に通知を受け取りたい場合に選択します。
      • [GDI スケーリング]: どのディスプレイに表示されているかに関係なく、グラフィックとテキストを正しいスケールでレンダリングする場合に選択します。

 
例えば、ある画面でディスプレイの拡大縮小の設定が
通常(100%)の場合と150%の場合では、このように見た目の差が生じ、
細かい文字が見えにくい方でも見やすくなります。
(TImage内の画像など、拡大されない項目も一部存在します。)

 


代替手段で拡大(または縮小)する

Delphi/400 XE7以前のバージョンをご利用の場合や、
何らかの理由で高DPIを有効にすることができない場合は、
代替として以下の方法で設定することも可能です。

対象フォームに対して「ScaleBy」メソッドを実行することで、
スケーリングを変更して見た目の大きさを変更できます。縮小も可能です。

この方法であれば、ユーザーの中で希望者だけが拡大(縮小)できるような記述が可能です。
また特定画面のみを常に拡大(縮小)させたい場合には、FormCreateで記述することも可能です。

<例>
  // フォームを150%にスケーリング
  Self.ScaleBy(3, 2);

「第1引数÷第2引数」の倍率になります。「3, 2」と指定した場合は150%になります。
※複数回実行した場合、拡大縮小した倍率からさらに拡大縮小が行われます。
 そのため、意図せず複数回走ることがないよう記述場所にご注意ください。

 


画面拡大(縮小)時における注意点

先述の通り、TImage内の画像など、一部の項目は拡大されません。

また、拡大縮小を行っていても画面内の座標は変わらないため
Height・WidthやTop・Leftを使用している画面では注意が必要です。

例えば下図のように、
  SpeedButton1.Top := 60;
  SpeedButton1.Left := 60;
というロジックがあった場合、
元々の(拡大縮小を無視した)指定ピクセルの位置にTopやLeftが設定されてしまいます。

実際は150%表示なのでTop・Leftともに90Pixelの所に出てほしいが・・・

こちらの解決にあたっては、
以下の2通りのいずれかをご検討ください。

1.高DPI非対応の設定を固定させる(11 Alexandria~)
高DPIの認識を[対応せず]に設定することで、
固定で100%スケーリングを想定してアプリケーションをレンダリングします。
これによって、高DPIの画面でもデフォルトのTopやLeftが設定されます。
(※ただし、100%スケーリングのため高DPIでは文字が少々ぼやけます。)
(※フォームのScaleByメソッドで拡大している場合は効きません。)

2.ロジックで倍率を計算する
GetDeviceCaps」というWindows API 関数を使用することで、
プライマリモニターの「テキスト、アプリ、その他の項目のサイズ」を取得することができます。
ここで取得した倍率を掛け算してTopやLeftにセットすることで、
想定の位置に設定ができるようになります。
(※複数モニター使用で、倍率が異なる場合も、プライマリモニターの設定値が取得されます。)
(※フォームのScaleByメソッドで拡大した場合は、ScaleByで拡大した倍率を使用します。)

 
<ロジック例>

{*******************************************************************************
 目的: 「テキスト、アプリ、その他の項目のサイズ」の倍率取得(※共通関数化)
 引数:
 戻値: 倍率(小数で、100%のときは1を返す)
*******************************************************************************}
function GetSizeOfTextAppsAndOtherItems: Currency;  // ※関数の名前は任意
var
  iDPI_X: Integer;
begin
  // プライマリモニターの「テキスト、アプリ、その他の項目のサイズ」を取得
  iDPI_X := GetDeviceCaps(GetDC(0), LOGPIXELSX);

  // 100%=96dpiに対する倍率を返す
  Result := iDPI_X / 96;
end;

{*******************************************************************************
 目的: ボタン押下時処理(高DPI設定の場合)
 引数:
 戻値:
*******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin
  // 取得した倍率を、設定したいTopやLeftに掛け算する
  SpeedButton1.Top  := Trunc(60 * GetSizeOfTextAppsAndOtherItems);
  SpeedButton1.Left := Trunc(60 * GetSizeOfTextAppsAndOtherItems);
end;

{*******************************************************************************
 目的: ボタン押下時処理(ScaleByを使用した場合)
 引数:
 戻値:
*******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin
  // ScaleByで拡大した倍率を直接掛け算する
  //(ここでは前項の『Self.ScaleBy(3, 2);』した場合を想定)
  SpeedButton1.Top  := Trunc(60 * (3 / 2));
  SpeedButton1.Left := Trunc(60 * (3 / 2));
end;

 

<関連リンク>