[Delphi] MainFormOnTaskBarとタスクバーボタン

Delphi2007 以降からでしょうか?MainFormOnTaskBar と言うプロパティが追加されています。

embarcadero のサイトでは下記のように説明されています。

MainFormOnTaskBar プロパティは、Windows タスクバー ボタンを VCL で扱う方法を制御します。

このプロパティが true の場合、タスクバー ボタンはアプリケーションのメイン フォームを表し、そのキャプションが表示されます。false の場合、タスクバー ボタンは、アプリケーションの(非表示の)メイン ウィンドウを表し、アプリケーションのタイトルが表示されます。
 
Windows Vista Aero 効果を使用するには、MainFormOnTaskBar が true であることが必要です。効果には、ライブ タスクバー サムネイル、動的ウィンドウ、Windows フリップ、Windows フリップ 3D があります。

このプロパティの登場というか、Windows Vista Aero 対応のために Delphi が行った修正によっていろいろとフォームの挙動が変更されました。

以前だと、フォームからフォームを表示しても、タスクバーにはアプリケーションのウィンドウのボタンが表示されていたため、何の変化もありませんでした。
しかし、今はメインフォームのボタンが表示されます。
これがどういうことかもう少しブレイクダウンします。

Form1 から Form2 を表示するアプリケーションを作ります。
Form1 のボタンをクリックすると Form2 を表示することとします。
このコードは下記のようになります。

procedure TForm1.Button1Click(Sender: TObject);
begin
  TForm2.Create(Self).Show;
end;

このアプリケーションを実行すると、タスクバーにはメインフォームである Form1 のボタンが表示されます。
Form2を表示しても同じです。

今度は、Form1 のボタンをクリックすると Form2 を表示し、Form1 はハイドすることとします。
以下のようなコードになります。

procedure TForm1.Button1Click(Sender: TObject);
begin
  TForm2.Create(Self).Show;
  Hide;
end;

このアプリケーションを実行して確認してみると、Form1 の表示時は先ほどと変わりないですが、Form2 を表示するとタスクバーから表示が消えてしまいます。メインフォームが消えてしまったからだと思われます。

これはちょっとまずいと思いました。くろねこ的には、現在アクティブなフォームのアイコンとキャプションを持ったタスクバーアイコンにしたいわけです。とりあえず、この内容を ActiveFormOnTaskBar と名づけます。Delphi で標準対応してほしいところですが、出来ないのでやり方を考えて見ます。

SetWindowLong と SetParent を使用します。

procedure TForm2.ShowTaskbarButton;
begin
  Windows.SetWindowLong(Handle, GWL_EXSTYLE, 
    Windows.GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW);
  Windows.SetParent(Handle, GetDesktopWindow);
end;

Form1を非表示にしない場合のタスクバーボタンのみ非表示にする関数

procedure TForm1.HideTaskBarButton;
begin
  ShowWindow(Handle, SW_HIDE);
  SetWindowLong(Handle, GWL_EXSTYLE,
    GetWindowLong(Handle, GWL_EXSTYLE) and not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW);
  ShowWindow(Handle, SW_SHOW);
end;

Form2を閉じたときにForm1のタスクバーボタンを元に戻す関数

// Form1側 ---
procedure TForm1.RestoreTaskBarButton;
begin
  Windows.SetWindowLong(Handle, GWL_EXSTYLE, FExStyle);
  Windows.SetParent(Handle, GetDesktopWindow);
end;
// FExStyle は、FormCreate で退避
procedure TForm1.FormCreate(Sender: TObject);
begin
  FExStyle := GetWindowLong(Handle, GWL_EXSTYLE);
end;

// Form2側 ---
procedure TForm2.FormDestroy(Sender: TObject);
begin
  if (Owner is TForm1) then
    with TForm1(Owner) do
    begin
      if not Visible then
        Show;
      RestoreTaskBarButton;
      Refresh;
    end;
end;

現在、だいたいいけるようになりましたが、Form2を表示している際のForm1のタイトルバーが変更されてしまっているのが気になります。外観の変更を伴わずに何とかならないですかね?

■参考:

コメント (0件)


くろねこ研究所
http://www.blackcatlab.com/article.php/ProgramingFAQ_del0081