戻る ホーム 上へ

SDI スタイル

最近 MS-Word や秀丸のように、SDIウィンドウから構成されるアプリケーションがトレンドです。これは

 

  1. 各ドキュメントウィンドウはモードレスで独立にメニューを持っている。
  2. プライマリウィンドウ(メインウィンドウ)がなく、各ウィンドウは対等である。
  3. 各ウィンドウはタスクバーに表示され、簡単に切り替えられる。個別に最小化と復帰ができる。
  4. 各ウィンドウはタスクマネージャや ALT-TAB で表示される。
  5. 全てのドキュメントウィンドウが閉じられるとアプリケーションが終了する。

というようになっています。これに対し Delphi がサポートする SDI形式の標準のアプリケーションスタイルは

  1. プライマリウィンドウ(メインフォーム)があり、プライマリウィンドウが閉じられるとアプリケーションが終了する。
  2. プライマリウィンドウ(メインフォーム)以外のフォームはタスクバー上にボタンを持たず、プライマリウィンドウ以外のフォームは最小化するとデスクトップ上の隅にちぢむ。
  3. プライマリウィンドウ(メインフォーム)を最小化すると、全てのウィンドウが非表示になる。
  4. ALT-TAB タスクマネージャに表示されるのは見えない「アプリケーションウィンドウ」で見えているウィンドウ(フォーム)は表示されない。

Delphi で前者のスタイルを実現するには以下の工夫が必要になります。

  1. メインフォームを非表示にする(つまりメインフォームは使わない)。
  2. アプリケーションウィンドウを非表示にする(アプリケーションウィンドウのボタンをタスクバーに表示しない)。
  3. 各フォームの拡張ウィンドウスタイルに WS_EX_APPWINDOW を加える(フォームのボタンをタスクバーに表示する)。
  4. 各フォームのオーナを「無し」にする(フォームをタスクマネージャや ALT+TAB で表示する)。
  5. 最後の表示されているフォームが閉じられる時、アプリケーションを終了する。

 

これを実現するフォームの雛型を以下に示します。フォームのテンプレートとしてご活用ください。

---------- メインフォームのソース ----------
unit NewMainForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TNewStyleMainForm = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

var
  NewStyleMainForm: TNewStyleMainForm;

implementation

{$R *.DFM}

procedure TNewStyleMainForm.FormCreate(Sender: TObject);
begin
  Application.ShowMainForm := False;  // メインフォームを非表示にする
end;

end.
---------- メインフォームのソース ----------
---------- サブフォームのソース ----------
unit NewSubForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TNewStyleForm = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormShow(Sender: TObject);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

var
  NewStyleForm: TNewStyleForm;
  NotFirstForm: Boolean;

implementation

{$R *.DFM}
// フォームが最後に閉じられるフォームかチェック
function IsLastForm(Form: TForm): Boolean;
var i: Integer;
    f: TForm;
begin
  Result:= True;
  for I := 0 to Screen.FormCount - 1 do begin
    F := Screen.Forms[I];
    if (f <> Form) and
       f.Visible and
       ((f.ParentWindow = 0) or f.HandleAllocated or
        not IsChild(f.Handle, f.ParentWindow)) then begin
      Result := False;
      Exit;
    end;
  end;
end;

procedure TNewStyleForm.CreateParams(var Params: TCreateParams);
begin
  inherited;

  if FormStyle in [fsNormal, fsStayOnTop] then  
    if BorderStyle in [bsSingle, bsSizeable] then begin
      Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; // タスクバーにボタン
      Params.WndParent := 0;                               // タスクマネージャにアイコン
    end;
end;

procedure TNewStyleForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if IsLastForm(Self) then Application.Terminate;  // 最後のフォームを閉じるなら
                                                   // アプリケーションを終了
end;

procedure TNewStyleForm.FormShow(Sender: TObject);
begin
  ShowWindow(Application.Handle,SW_HIDE); // アプリケーションウィンドウがタスクバーに
                                          // 表示されるのを防ぐ
  if not NotFirstForm then begin
    NotFirstForm := True;
    case CmdShow of // 最初に表示されるフォームは CmdShow に従う
      SW_SHOWMINNOACTIVE: WindowState := wsMinimized;
      SW_SHOWMAXIMIZED:   WindowState := wsMaximized;
    end;
  end;
end;

end.
---------- サブフォームのソース ----------

戻る ホーム 上へ

inserted by FC2 system