戻る ホーム 上へ 進む

Owned Window を使いたい

Tip & 解説

Windows の標準アプリケーション「メモ帳」の「検索ダイアログ」の様に、 特定のウィンドウより常に手前に表示されるウィンドウを Owned Window といいます。

Owned Window は Owner Window に「所有」された Windows で、Owner Window より常に手前に表示され、 Owner Window が最小化されると Owned Window は自動的に非表示になり、 Owner Window が破壊されると Owned Winodow は自動的に破壊されます。

Delphi のフォームは Owned Window をサポートしていないので、 Delphi で作ったアプリケーションは、 フォームのZオーダがマウスクリックで自由に変更できてしまいます。 例えば、検索ダイアログをフォームとして作成して表示しても、 メインウィンドウをクリックすると、 検索ウィンドウがメインウィンドウの後ろに表示されてしまいます。

ほとんどの場合はフォームのスタイルを fsStayOnTop にすれば、 Zオーダに関しては Owned Window とほぼ同じことが実現できますが、 Owned Window ほどの柔軟性がありません。

フォームを Owned Window にしたい場合は、

type
  TOwned = class(TForm)
  private
    OwnerForm: TForm;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor CreateOwnedForm(AOwner: TComponent; AOwnerForm: TForm);
  end;

 (略)

constructor TOwned.CreateOwnedForm(AOwner: TComponent; AOwnerForm: TForm);
begin
  OwnerForm := AOwnerForm;
  Inherited Create(AOwner);
end;

procedure TOwned.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.WndParent := OwnerForm.Handle;
end;

として、フォームを作成するときに
    TOwned.CreateOwnedForm(Application, 「Owner Window になるフォーム」);

とすればうまくゆきます。Owned Window になるフォームは必ず 「選択可能なフォーム」にして実行時にフォームを作ってください。

ここまでは簡単なのですが、Delphi で Owned Window を扱うには、 メインフォームへの処理追加が必要です。

Delphi のアプリケーションは、実は見えない「アプリケーションウィンドウ」 を持ち、すべてのフォームは「アプリケーションウィンドウ」の Owned Window になっています。 メインフォームを最小化するとすべてのフォームが自動的に非表示になるのは、 VCL がメインフォームの最小化をトラップして「アプリケーションウィンドウ」 を最小化するためです(下図参照)。

Figure 3.1

アプリケーションウィンドウとフォームの関係

フォームを別のフォームの Owned Window にした場合、 「アプリケーションウィンドウ」 から見ると孫の Owned Window になります。残念ながら、Windows は Owner Window が最小化するときに Owned Window を非表示にする処理を、 Owner Window が直接「所有」する Owned Window までしか行ってくれません。 ですから、上記の手法だけでは、メインフォームを最小化しても、Owned Window が画面に表示されたまま残ってしまいます(下図参照)。

Figure 3.1

この問題を解決するには、「アプリケーションウィンドウ」が最小化するとき、 すべてのフォームを非表示にすればうまくゆきます。幸い、TApplication には、 OnMinimize と OnRestore イベントがあるため、簡単に処理が追加できます。

{フォーム作成時に「アプリケーションの最小化/復旧」
 時のイベントハンドラを設定する}
procedure TMain.FormCreate(Sender: TObject);
begin
  Application.OnMinimize := AppMinimized;
  Application.OnRestore   := AppRestored;
end;

{「アプリケーション最小化時」、すべてのフォームを非表示にする}
{Visible Property をセーブするのに、通常フォームでは使わない
 Tag Property を使うことにした。}

{Delphi 3.0J ではメインフォームの Visible Property を
 False にするとタスクバー上のウィンドウボタンが消えるため
 メインフォームのみ Visible を変更しない}

procedure TMain.AppMinimized(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to Screen.FormCount -1 do
    if Screen.Forms[i] <> Application.MainForm then
      with Screen.Forms[i] do begin
        tag :=  LongInt(Visible); Visible := False;
      end;
end;

procedure TMain.AppRestored(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to Screen.FormCount -1 do
    if Screen.Forms[i] <> Application.MainForm then
      with Screen.Forms[i] do Visible := Boolean(tag);end;

最後に、注意事項が一つだけ有ります。Owned Window を使う場合、 利用者は Owner Window が閉じられると、 Owned Window も自動的に閉じられることを期待します。 しかし、Delphi では「自動作成の対象」のフォームは、閉じられる時、 デフォルトでは Hide されるだけなので、Owned Window が閉じられません。 Owner Window を閉じる際は、かならず、フォームを解放するようにしてください。

 

戻る ホーム 上へ 進む inserted by FC2 system