アプリケーションの場所を記憶(マルチディスプレイ対策)

 何を今更?...そうですね、アプリケーション終了時にフォームの Top / Left / Width / Height をレジストリや Ini ファイルに保存し、起動時にその値を読み込めばいいだけですよね...って、本当にそうですか?

 マルチディスプレイ環境があったとします。

  1. アプリケーションをセカンダリディスプレイで終了。
  2. セカンダリディスプレイを撤去。
  3. アプリケーションを起動。
 さて、このアプリケーションをどうやってプライマリディスプレイに表示させましょうか? 殆どの Delphi アプリケーションはタスクバーのボタンを右クリックして "移動" を選択する事ができませんよ?

// Form表示時
  dTop     := Reg.ReadInteger(REG_PATH,'FORMTOP'   ,0);
  dLeft    := Reg.ReadInteger(REG_PATH,'FORMLEFT'  ,0);
  if GetSystemMetrics(SM_CMONITORS) <> Reg.ReadInteger(REG_PATH,'MONITORS' ,1then
    begin
      if dTop  > Screen.Height then
        dTop  := dTop  mod Screen.Height;
      if dLeft > Screen.Width  then
        dLeft := dLeft mod Screen.Width;
    end;
  Top  := dTop;
  Left := dLeft;

 

// Form破棄時
  Reg.WriteInteger(REG_PATH,'MONITORS' ,GetSystemMetrics(SM_CMONITORS));

 アプリケーション終了時にモニタの数を保存しておき、起動時に保存されているモニタの数と現在のモニタの数を調べて、モニタの数が違ったらアプリケーションを強制的にプライマリディスプレイへ移動する等の措置が必要となります。


フォームの位置?(マルチディスプレイ対策)

 マルチモニタを意識したアプリケーションでは、メインフォーム等は位置を記憶するにしても、ダイアログ等はメインフォームのあるディスプレイの中央に表示させると目線の移動が少なくて済みます。これを行うにはフォームの Position プロパティに "poScreenCenter" を設定するだけです。めでたし、めでたし...って、本当にそうでしょうか?

 実は Position プロパティに "poScreenCenter" を設定していてもメインフォームのあるディスプレイに表示されないケースがあります。例えば、フォームを動的作成する時にメインフォームを親 (Owner) として設定しなかった場合です。スプラッシュウィンドウ等は仕方がないかもしれませんね。

 そしてレアケースですが、Position プロパティに"poScreenCenter" を設定し、メインフォームを親 (Owner) としてもメインフォームのあるディスプレイの中央に表示されない事があります。古い Delphi で作られたフォームを別のフォームから派生して作った場合です。ちょっとややこしいですが、

  1. TBaseDialog = Class(TForm);
  2. TTestForm = Class(TBaseDialog);
 この"2." に該当するフォームです。これを解消するには、
  1. 継承フォームをテキスト形式 DFM に変換。
  2. 継承フォームをプロジェクトから削除。
  3. 継承元フォームをテキスト形式 DFM に変換。
  4. 継承元フォームをプロジェクトから削除。
  5. 一旦保存して Delphi を終了。
  6. 継承元フォームをプロジェクトに追加。
  7. 継承フォームをプロジェクトに追加。
  8. 再構築
 ...このようにするしかありません。そして、念のために DefaultMonitor プロパティを "dmMainForm" あるいは "dmActiveForm" に変更しておきましょう。


 BACK