Delphi Tips 
-----------------------------

キーワード:フォーム

>> Index

03/04 フォームの最小化時のアニメーション効果を出す(BCB)
05/17 Photoshop のようなツールウィンドウを実現したい
05/17 OnShow イベント中で SetFocus すると不具合
06/02 フォームの新規作成のデフォルトを変更したい
12/22 フォームを1つずつ表示する
09/27 アプリケーションを常駐させてタスクトレイに登録したい
09/20 フォームのアイコンをアニメーションにしたい
09/06 メインフォーム以外のフォームをタスクバーに入れたい。
09/06 APPのフォームを最小化して起動したい
09/06 カーソルキーでボタン(TButton)のフォーカス移動をやめさせたい
09/01 フォームの最小化、最大化をアニメーションでやりたい。(DELPHI)
08/30 メインフォーム以外のフォームを最小化した時もAPP全体を最小化したい
02/11 フォームの破棄、生成を続けて行うときの注意事項
02/11 Delphi2 以上で Form の枠を黒線一本にするには
02/11 アプリケーションが最小化されているかどうかを判定する
02/11 Form をスクロールして特定のコントロールを表示させる
02/08 Scaled/AutoScrollプロパティと実行時のフォームサイズ
02/08 起動時にフォームの表示・非表示を決める
02/08 サブフォームがアクティブな時はメインフォームのアクセラレータキー・ショートカットキーを無効にしたい
02/08 アイコン状態で起動するアプリ
02/08 フォームの印刷時にComboBoxの内容が印刷されない
02/08 設計時にフォームがエラーで読み込めず変更もできない

最終更新: 7568 日前

0057  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2004/03/04 osamu 編集
フォームの最小化時のアニメーション効果を出す(BCB)

BCBで作成したアプリだけは、他のアプリと異なり、Win95で「アイコン化」したときなどのタイトルバーのアニメーション(タイトルバーがひゅるるっとタスクバーに吸い込まれるようなアレ)が出ないようなのですが、これはBCBの仕様なのでしょうか?あるいは出す方法があるとか??
  Delphiでもそうですよ!!

 これは、BCB が使用しているライブラリ VCL の仕様のようです。

 アニメーションを実現するには、プログラムを組む必要がありますが、(別項でDELPHIでのコード例を見て下さい)
既にこのようなコンポーネントが発表されています。

http://www.delphianworld.com/direct.html?id=SY0042

TAnimateWindowというのがそれのようです。
参照: [Delphi-ML:34432] [builder:4884] <Windows>

0327  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
Photoshop のようなツールウィンドウを実現したい

1.細いタイトルバーでクローズボタンのみが付いている
2.アプリケーションがアクティブであればツールウィンドウのタイトルバーもアクティブ色
3.常にアプリケーションのフォームよりも手前にある

というようなツールウィンドウを実現しようと思うと、フォーカス関連のイベントが貧弱な Delphi ではなかなか難しいようです。

[Delphi-ML:66799][Delphi-ML:66801] で書かれているように、アプリケーションに飛んでくるすべてのメッセージの中からフォーカスの移動に関係するものをチェックしてやることで実現が可能です。実際のツールウィンドウはコード中の TToolWindow を継承して作成することになります。
参照: [Delphi-ML:66799] <アプリケーション>

0318  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2002/05/17 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2002/05/17 osamu 編集
OnShow イベント中で SetFocus すると不具合

フォームにMemoを貼り付けて実験してみたのですが

procedure TForm1.FormShow(Sender: TObject);
begin
  Memo1.SetFocus;
end;

とすると「ソフトを起動したとき、それがアクティブウィンドウになるにもかかわらず、そのソフトを示すタスクバーのボタンが押されない状態で表示される」という症状が出るようです。

Memo1 の TabOrder をゼロにするなど、別の方法でフォーカスをコントロールする必要があるようです。
参照: [Delphi-ML:67321] <アプリケーション>

0310  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2001/06/02 濱野 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/06/02 濱野 編集
フォームの新規作成のデフォルトを変更したい

例えばはじめからScaled=Falseにしたい、
文字は固定ピッチで大きめのフォントにしたい、
フォームの位置、大きさ、表示状態を最大化で標準化したい、etc....

こういう時、元になるフォームを[プロジェクト]-[リポジトリに追加]
でリポジトリに登録しておき、[ツール]-[リポジトリ]で登録した
フォームを選択して、[フォームの新規作成時に使用]にチェックを入れて
おけばスピードバーや[ファイル]-[フォームの新規作成]を選んだときに
リポジトリに登録したものと同じ内容でフォームを作成することが出来ます。

ただしあくまでもコピーが作成されるだけなので元のフォームを変更しても
その変更は反映されません。そのような変更が予想される場合は[ファイル]
-[新規作成]で[継承]を選んで使用すると後々便利です。

コントロールのデフォルト変更には[コンポーネント]-
[コンポーネントテンプレートの作成]を使用するといいでしょう。
Delphi 5からはさらにフレーム機能という便利な機能もあります。
参照: <開発環境>

0295  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/12/22 濱野 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/12/22 濱野 編集
フォームを1つずつ表示する

TFormの配列をスタック風に管理し、呼び出し元は
呼び出されたフォームを表示後、非表示にします。
これでフォームが1つずつ表示されるようになります。
前のフォームへの復帰も再表示するだけなので速いです。

この手続きにちょっと手を加える事で位置やサイズを
揃える事も出来ます。


unit FmDsp;

interface
uses
  Windows, Messages, SysUtils, Classes, Forms;

  procedure SetMainForm(MainForm: TForm);
  procedure ShowNextForm(FormClass: TFormClass; Form: TForm);
  procedure ShowPrevForm;

implementation

type
  TShowType = (stWithCreate, stShowOnly);
  TFormRec = record
    Form: TForm;
    ShowType: TShowType;
  end;

var
  FormAry: array[0..100] of TFormRec;
  FormTop: Integer = 0;

{ 最上階のフォームの登録、プログラムのスタートアップ時
  に一回だけ呼び出す。 }
procedure SetMainForm(MainForm: TForm);
begin
  FormAry[0].Form := MainForm;
  FormAry[0].ShowType := stShowOnly;
  FormTop := 0;
end;

{ 次のフォームの表示
  FormClass: フォームのクラス名
  Form: フォーム変数名、フォームが自動作成でない場合 nilを指定 }
procedure ShowNextForm(FormClass: TFormClass; Form: TForm);
begin
  Inc(FormTop);
  if Form = nil then
  begin
    FormAry[FormTop].Form := FormClass.Create(Application);
    FormAry[FormTop].ShowType := stWithCreate;
  end else
  begin
    FormAry[FormTop].Form := Form;
    FormAry[FormTop].ShowType := stShowOnly;
  end;

  FormAry[FormTop].Form.Show;
  FormAry[FormTop - 1].Form.Hide;
end;

{ 前のフォームの表示、呼び出された側のフォームのCloseイベントで呼び出し }
procedure ShowPrevForm();
begin
  FormAry[FormTop - 1].Form.Show;
  if FormAry[FormTop].ShowType = stWithCreate then
    FormAry[FormTop].Form.Release
  else
    FormAry[FormTop].Form.Hide;
  Dec(FormTop);
end;

end. { unit FmDsp }
参照:

0207  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/19 西坂良幸 rev 1.10
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
アプリケーションを常駐させてタスクトレイに登録したい

コンポーネントをつかう人が多いんでしょうね。MLでは少ない話題です。このようなAPLを何十本も作るんでなければ、直接コーディングしてみませんか。
要領は、APIのShell_NotifyIcon関数を使うことです。TaskTrayへの登録と削除は簡単にできます。
頭を悩ますのは、どんなアイコンを使うのかと、TaskTrayに送られてくるメッセージを自分で決めなければならないことです。

const
  WM_MY_TRAYICON = WM_APP + $300; // 適当です

// ProcessMesageに配慮−−無くても良い
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // WM_QUIT メッセージを受け取る時
  if Application.Terminated then
  begin
    ShowWindow(Application.Handle, SW_HIDE);
    Visible := False;
    Action := caNone;
  end;
end;

// アイコンをトレイに登録−−ここではメインアイコンを使用
procedure TForm1.CreateTaskBarIcon;
var
  NotifyData: TNotifyIconData;
begin
  with NotifyData do
  begin
    cbSize := SizeOf(TNotifyIconData);
    Wnd    := hWndTrayIcon;
    uID    := 0;
    uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
    szTip  := 'Traybar Tip';
    hIcon  := Application.Icon.Handle;
    uCallbackMessage := WM_MY_TRAYICON;// 独自に定義
  end;
  Shell_NotifyIcon( NIM_ADD, @NotifyData );
end;

// アイコンを削除
procedure TForm1.DeleteTaskBarIcon;
var
  NotifyData: TNotifyIconData;
begin
  with NotifyData do
  begin
    cbSize := SizeOf(TNotifyIconData);
    Wnd    := hWndTrayIcon;
    uID    := 0;
  end;
  Shell_NotifyIcon( NIM_DELETE, @NotifyData );
end;

// 起動直後はトレイにアイコン表示のみ
procedure TForm1.FormCreate(Sender: TObject);
begin
  // uTaskBarRecrate は TForm1 の private に UINT 型で宣言
  // 新しい UtilWindow を作成し、ブロードキャストメッセージのみを受け取らせる
  uTaskBarRecreate := RegisterWindowMessage('TaskbarCreated');
  // hWndTrayIcon は TForm1 の private に HWND 型で宣言
  // メッセージ送信先を指定
  hWndTrayIcon := AllocateHWnd(TaskTrayWndProc);

  CreateTaskBarIcon;
  ShowWindow(Application.Handle,SW_HIDE);
  Application.ShowMainForm := False;
end;

// 終了した時にトレイのアイコンを削除
procedure TForm1.FormDestroy(Sender: TObject);
begin
  DeleteTaskBarIcon;
  DeallocateHWnd(hWndTrayIcon);
end;

// タスクトレイに来るWM_MY_TRAYICONメッセージを受信
procedure TForm1.TaskTrayWndProc(var Msg: TMessage);
var
  ps: TPoint;
begin
  Case Msg.LParam of
    WM_LBUTTONDBLCLK:
      begin
        Visible := true;
        ShowWindow(Application.Handle,SW_SHOW);
        //ShowWindow(Application.Handle,SW_RESTORE);
      end;
    WM_RBUTTONUP:
      begin
        GetCursorPos(ps);
        SetForegroundWindow(Handle);
        // フォームにポップアップメニューがあるとする
        PopupMenu1.Popup(ps.x,ps.y);
        PostMessage(Handle, WM_NULL, 0,0);
      end;
    else
      // タスクバーが移動・再構築された場合に消えたアイコンを再生成
      if (Msg.LParam = LongInt(uTaskBarRecreate)) then
        CreateTaskBarIcon;
  end;
end;

AllocateHWnd 関数の戻り値のウィンドウハンドルを利用すれば他のメッセージ受信先/送信先として利用できるので、TrayIcon のメッセージ送信先に利用しました。
参照: [Delphi-ML:2536] [Delphi-ML:11821] [Delphi-ML:35250] <System> <Windows> <コンポーネント >

0265  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/19 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/20 西坂良幸 編集
フォームのアイコンをアニメーションにしたい

タイマーイベントを使って、AppliCationのアイコンをきりかえてやればアニメーションGIFのような効果ができます。

プロジェクトの*.resファイルに、アイコン'ICON1'-'ICON5'をアニメ風に作成して下さい。

フォームにStartBtn、StopBtn の2個のボタンとTTimer(Intervalプロパティを100程度)を貼り付けます。
  private 部に
    IconStat: integer;
    ICon1,ICon2,ICon3,ICon4,ICon5: TIcon;
と書き加えます。

// あらかじめリソースを参照するアイコンを作成
procedure TForm1.FormCreate(Sender: TObject);
begin
  ICon1 := TIcon.create;
  ICon1.Handle := LoadIcon(HInstance,'ICON1');
  ICon2 := TIcon.create;
  ICon2.Handle := LoadIcon(HInstance,'ICON2');
  ICon3 := TIcon.create;
  ICon3.Handle := LoadIcon(HInstance,'ICON3');
  ICon4 := TIcon.create;
  ICon4.Handle := LoadIcon(HInstance,'ICON4');
  ICon5 := TIcon.create;
  ICon5.Handle := LoadIcon(HInstance,'ICON5');
  Application.Icon.Handle := ICon1.Handle;
  IconStat := 1;
end;

// 破棄
procedure TForm1.FormDestroy(Sender: TObject);
begin
  ICon1.Free;
  ICon2.Free;
  ICon3.Free;
  ICon4.Free;
  ICon5.Free;
end;

// スタート
procedure TForm1.StartBtnClick(Sender: TObject);
begin
  Timer1.Enabled := true;
end;

// ストップ
procedure TForm1.StopBtnClick(Sender: TObject);
begin
 Timer1.Enabled := false;
 IconStat := 1;
 Application.Icon.Handle := ICon1.Handle;
end;

// タイマーイベントでアイコンの切り替え
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  If IconStat = 5 then IconStat :=1
  else IconStat := IconStat + 1;
  Case IconStat of
  1: Application.Icon.Handle := ICon1.Handle;
  2: Application.Icon.Handle := ICon2.Handle;
  3: Application.Icon.Handle := ICon3.Handle;
  4: Application.Icon.Handle := ICon4.Handle;
  else Application.Icon.Handle := ICon5.Handle;
  end;
end;


4−5個アイコンを作るとスムースです。
注意事項として。resファイルを書き直した時は、[プロジェクトの再構築]を行ってから実行して下さい。resの変更が反映されません。また、アイコンの名称はイメージエディタでは、デフォルトでIcon?となりますので、オリジナルな名称に変えて下さい。

また、イメージリストを使えば、以下のようにすれば、ほぼ同じ結果が得られます。

var
  IconCount : integer;
procedure TForm1.Button1Click(Sender: TObject);  // start
begin
    Timer1.Interval := 100;
    Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
    if IconCount >=ImageList1.Count then IconCount := 0;
    ImageList1.GetIcon(IconCount, Application.Icon);
    inc(IconCount);
end;

この場合は、使用するアイコンイメージは、リソースに入りませんので、プログラムアイコンとして使用出来ません。必要ならば、リソースからイメージリストへロードする処理を加えて下さい。
参照: [Delphi-ML:42725] [Delphi-ML:42748] <アイコン>

0005  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
メインフォーム以外のフォームをタスクバーに入れたい。

フォームのウィンドウスタイルにWS_EX_APPWINDOWを加えます。

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

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree; // これを忘れないこと
 Form2 := nil;
end;

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;

とします。[Delphi-ML:7921]

また、タスクバーにも入れたくないときは、
 Application.OnMinimize := AppMinimize;
を設定し、

procedure TForm2.AppMinimize(Sender: TObject);
begin
   ShowWindow(Form1.Handle, SW_HIDE);
end;

ですね。
参照: [Delphi-ML:3429] [Delphi-ML:6234] [Delphi-ML:17682] <タスクバー> <Windows>

0232  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/01 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
APPのフォームを最小化して起動したい

メインフォームのWindowStyleをwsMinimizedに設定しておくと自分で起動するときは、最小化されタスクバーに入ります。
しかし、他のAPPから起動する時やAPIのShowWindowやショートカットやタスクトレイなどで起動する時はちょっとやっかいです。
これは、Application(変数)のフォームとメインフォームの同期がとれないからです。これはメインフォームに送られてくるスタイルフラッグに合わせて、Applicationのスタイルを合わせてやる必要があります。
この方法は、MLではいくつも紹介されています。[Delphi-ML:13173] [Delphi-ML:13185]
(混乱ということでは、古いバージョンでは、GetStartupInfoで取得できるwShowWindow値が、CmdShowと必ずしも一致しないという問題や、D2→D3で仕様が変わっているということもあります。)

以下のコードはどうでしょうか。

procedure TForm1.FormCreate(Sender: TObject);
var
  SI : TStartupInfo ;
begin
  // D4では、常にCmdShow = SI.wShowWindowですが念のため
  GetStartupInfo( SI ) ;
  CmdShow := SI.wShowWindow ;

  // 最小化に関係するスタイルフラッグにすべて対応
  case cmdShow of
    SW_SHOWMINIMIZED,
    SW_MINIMIZE,
    SW_SHOWMINNOACTIVE :
      Application.Minimize ;// 同期させる
  end ;
end;


なお、子フォームの場合をDeskTopでなく、タスクバーに入れるには、0005番「メインフォーム以外のフォームをタスクバーに入れたい。」を参照して下さい。
参照: [Delphi-ML:13173] [Delphi-ML:3426] [Delphi-ML:23218] [Delphi-ML:25557] <タスクバー> <Windows>

0237  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/06 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/06 西坂良幸 編集
カーソルキーでボタン(TButton)のフォーカス移動をやめさせたい


TButtonのOnKeyPress、OnKeyDownなどでやってみてもダメですね。これは、Windowsのボタンの仕様です。
フォームへのCM_DialogKeyメッセージをとらえて処理すると可能です。

procedure TForm1.CMDialogKey(var Msg:TCMDialogKey);
begin
    case Msg.CharCode of
    VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT :  Msg.CharCode:=0;
    end;
    inherited;
end;


このメッセ−ジはタブキー(VK_TAB)もとらえることが出来ます。
参照: [Delphi-ML:3691] [Delphi-ML:33541] <コンポーネント > <Standard>

0228  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/29 西坂良幸 rev 1.4
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/01 西坂良幸 編集
フォームの最小化、最大化をアニメーションでやりたい。(DELPHI)


過去のMLを検索してみましたが案外少ないようです。「最小化」の話題は結構あるのに。このような機能をもつコンポーネントがたくさんあるし、あまり重要な機能でもないということですか。

これは当然ですが、SetBoundsメソッドなんかをいじっていてもダメですね。
また、WM_SYSCOMMANDメッセージをとらえて
procedure TForm1.WMSysCommand(var msg: TWMSysCommand);
begin
  if msg.CMdType = SC_MINIMIZE then
    WindowState := wsMinimized;
  inherited;
end;

としてもだめですね。[Delphi-ML:939]

結論的に言うと、MovWindowというAPIを使うんですが、このためのちょっとした工夫が、メッセージの理解やその処理の仕方について大変勉強になります。(コンポーネント貼り付けるだけが能ではない!)

ということで、今回はちょっと解説を。
・フォーム(メインも含めて)とApplicationの同期を考慮しなければならないので、双方のWindProcをオーバーライドしなければならない。
・自分のメソッドのWindProcは、オーバーライドは簡単ですよね、
・では、ApplicationのWndProcはどうすればオーバーライドのようにできるのか。
というようなことを考えて下さい。

  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    N1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;        // ボタンではなく、メニューでテストがミソ
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure N1Click(Sender: TObject);
    procedure N2Click(Sender: TObject);
  private
    NewAppWndProc: Pointer;
    OldAppWndProc: Pointer;
  protected
    procedure WndProc(var Msg: TMessage); override;
    procedure AppWndProc(var Msg: TMessage); virtual;
  public
  end;

//  途中省略

uses MMSystem;

{$R *.DFM}
// AppliCationのWndProcをすり替えている
procedure TForm1.FormCreate(Sender: TObject);
begin
  if Application.MainForm = nil then
  begin
    // WndProcのインスタンスを作成
    NewAppWndProc := MakeObjectInstance(AppWndProc);
    // 元のApplicationのWndProcアドレスを保存
    OldAppWndProc := Pointer(GetWindowLong(Application.Handle, GWL_WNDPROC));
    // ApplicationのWndProcアドレスをNewAppWndProcに変更
    SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(NewAppWndProc));
  end;
end;

// 終わる時は後始末をする
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if (Application.Handle <> 0) and (OldAppWndProc <> nil) then
  begin
    // 元のWndProcに戻す
    SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(OldAppWndProc));
    // インスタンスを解放
    FreeObjectInstance(NewAppWndProc);
  end;
end;

//ウィンドウプロシージャを書き直す
procedure TForm1.WndProc(var Msg: TMessage);
var
  SaveTitle: string;
begin
  with Msg do  // ここでメッセージを横取り
  begin
    if (Msg = WM_SYSCOMMAND) and (WParam = SC_MINIMIZE) then
      with Application do
      begin
        SaveTitle := Title;
        Title := Caption;
        // 再び手前に表示−−おまじない
        NormalizeTopMosts;
        // トップ レベルでアクティブ ウィンドウ化
        SetActiveWindow(Handle);
        // ウィンドウの位置と寸法を変更
        MoveWindow(Handle, Left, Top, Width, Height, True);
        // サウンドを再生  ふろくだから無視してください
        PlaySound('Minimize', 0, Snd_Alias or Snd_NoDefault or Snd_ASync);
        // 表示状態を設定
        ShowWindow(Handle, SW_MINIMIZE);
        Title := SaveTitle;
      end
  end;
  inherited WndProc(Msg);
end;

//アップリケーションプロシージャに置き換えられた偽のWndProc
procedure TForm1.AppWndProc(var Msg: TMessage);
begin
  with Msg do     // ここでも横取りする
  begin
    if (Msg = WM_ERASEBKGND) then
      Result := 1
    else if (Msg = WM_SYSCOMMAND) and (WParam = SC_RESTORE) then
      with Application do
      begin   // 戻す
        PlaySound('RestoreUp', 0, Snd_Alias or Snd_NoDefault or Snd_ASync);
        // トップ レベルでアクティブ ウィンドウ化
        SetActiveWindow(Handle);
        ShowWindow(Handle, SW_RESTORE);
        // わり算を大きくするとスム−ス
        MoveWindow(Handle, Screen.Width div 4, Screen.Width div 4, 0, 0, False);
        Result := 1;
      end
    else if (Msg = WM_SYSCOMMAND) and (WParam = SC_MINIMIZE) then
    begin    // 最小化
      PlaySound('Minimize', 0, Snd_Alias or Snd_NoDefault or Snd_ASync);
      // フォーム
      Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0);
    end
    else
      Result := CallWindowProc(OldAppWndProc, Application.Handle, Msg, WParam, LParam);
  end;
end;


これをヒントに自分でコンポーネント化するのは簡単でしょう。
もう一つ、フォームへのメッセージを横取りするWndProcをコンポーネントで書くということです。

MLで話題になっていたので、ひとこと。ボタンやメニューで最小化する時は

procedure TForm1.N1Click(Sender: TObject);
begin
  Application.minimize;  // これはダメ アニメーションしない(当然)
end;

procedure TForm1.N2Click(Sender: TObject);
begin
  Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0); // これでうまくいく
end;

逆のRestoreの場合は、
  Application.minimize;
  Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
でも似たようなものになります。
なぜか?  → MLを再読されたし。
参照: [Delphi-ML:939] [Delphi-ML:34432] <Windows>

0227  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/29 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/30 osamu 編集
メインフォーム以外のフォームを最小化した時もAPP全体を最小化したい


複数のフォームを持つAPPで、メインフォームでないフォームのMiniMizeボタンを押すとこのフォームは左下にタイトルバー形式にアイコン化され、メインフォームはそのまま残っています。これはこれで意味があるのですが、どのフォームを最小化してもAPP全体を最小化したい時があるものです。

これは、WM_SYSCOMMANDメッセージをとらえて、Appicationを最小化すればできます。

// Form2は、メインフォームでないフォームです。

type
  TForm2 = class(TForm)
    // コントロールいろいろ
  private
    procedure WMSysCommand(var Message: TWMSysCommand);message WM_SYSCOMMAND;
  public
    { Public 宣言 }
  end;

var
  Form2: TForm2;

implementation

{$R *.DFM}

procedure TForm2.WMSysCommand(var Message: TWMSysCommand);
begin
 if (Message.CmdType and $FFF0 = SC_MINIMIZE) then
    Application.Minimize
  else
    inherited;
end;


最小化された状態の判定は、
  IsIconic(Application.Handle); で行います

「元のサイズに戻す」のは、
  Application.Restore;    ですね。

TCustomFormのWM_SYSCOMMANDメッセージ処理は

  if (Message.CmdType and $FFF0 = SC_MINIMIZE) and
    (Application.MainForm = Self) then
    Application.Minimize
  else
    inherited;

のようになっていることからもわかるように、本来メインフォームとApplicationフォームとは別のものです。
この違いからWindowStyleプロパティの独特の仕様が生まれているのでしょうか?
左下にアイコン化するときは、WindowStyleプロパティは変化しないようです。フォームのWindowStyleプロパティは、メインフォームでないときは注意が必要です。
参照: [Delphi-ML:25286] [Delphi-ML:40312] <Windows>

0166  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
フォームの破棄、生成を続けて行うときの注意事項

> プログラム中でフォームを破棄し、直後に生成するとイベントが妙な順で
> 発生してしまい困っています。
>
>   Form1.Release;
>   :
>   Form1 := TForm1.Create( Application );
>   :
>   Form1.Show;
>   処理A
>
> と、こんな感じで記述すると、Form1 の Create イベントや処理 A の後に、
> Form1のDestroy イベントが走っているようなのです。

Release の後で Application.ProcessMessages してみるとどうですか。Release のヘルプを見てみてください。
Form1 がアクセスされていないことが分かっているのなら、Free でも良いです(場合によって推奨されない方法です)。
参照: [Delphi-ML:31893]

0154  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
Delphi2 以上で Form の枠を黒線一本にするには

Form の枠を一本線にするために Ctrl3D = True, BorderStyle = bsSingle としても、望みの結果が得られません。問題は、ControlStyle に csFrame が無いとき CTRL3D := False は無視されてしまうということです。

constructor を再定義して

# constructor TForm1.Create(AOwner: TComponent);
# begin
#   inhelited;
#   ControlStyle := ControlStyle + [csFramed] ;
# end;

を加えれば望みの結果が得られます。
参照: [Delphi-ML:30137] <バグ>

0148  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
アプリケーションが最小化されているかどうかを判定する

最小化された状態の判定:

  IsIconic(Application.Handle)

「元のサイズに戻す」

Application.Restore;

で良いと思います。
参照: [Delphi-ML:25293] <アプリケーション>

0145  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
Form をスクロールして特定のコントロールを表示させる

TForm には ScrollInView / AutoScrollInView などという便利なメソッドがあります。
参照: [Delphi-ML:25041]

0054  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
Scaled/AutoScrollプロパティと実行時のフォームサイズ

中村@NECさんの、[builder-ML:4674] からの引用です。

(1) Scaled = False, AutoScroll = False

    フォームのフォントの大きさ、フォームのクライアント領域、
    コントロールの大きさは設計時のピクセル単位のサイズが
    そのまま使われる。

(2) Scaled = False, AutoScroll = True

    (1) とほとんど同じだが、フォームは Width と Height で大きさが
    設定されるので、タイトルバーの高さ、枠の幅、メニューの高さ
    によりクライアント領域の大きさが若干かわるので、場合によっては
    コントロールがはみ出したりする。

(3) Scaled = True, AutoScroll = False

    フォームのフォントの大きさ、フォームのクライアント領域、
    コントロールの大きさは設計時のピクセル単位のサイズに
    フォントの大きさの変化に応じたスケール比を掛けたものが
    使われる。

(4) Scaled = True, AutoScroll = True

    フォームのフォントの大きさ、コントロールの大きさは設計時の
    ピクセル単位のサイズにフォントの大きさの変化に応じた
    スケール比を掛けたものが使われる。しかし、フォームの
    大きさは設計時のピクセル単位の大きさがそのまま使われるので
    コントロールがはみ出したりする。使わない方がよいでしょう(^^


Delphi-MLで詳しく解説してくださったのが [Delphi-ML:19661]
参照: [Delphi-ML:19661]

0056  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
起動時にフォームの表示・非表示を決める

Main Form の表示は Application の ShowMainForm と Main Form の Visible Property で決まります。
Application.Run が呼ばれる前に ShowMainForm を適切に設定して下さい。
参照: [Delphi-ML:19468]

0109  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
サブフォームがアクティブな時はメインフォームのアクセラレータキー・ショートカットキーを無効にしたい

メインフォームのメニューに指定されたアクセラレータキー([File(&F)]とした時の 'F')は、サブフォームがアクティブであっても、そのサブフォームがメインメニューを持たない場合には、メインフォームのメニューを起動してしまいます。
また、メインフォームのメニューに指定されたショートカットキー([Open(&O)... Ctrl+O] とした時の 'Ctrl+O')は、サブフォームがアクティブである場合にも有効です。

これらを回避するには以下のようにします。

function TForm1.Hook(var Message: TMessage): Boolean;
begin
  case Message.Msg of
  CM_APPKEYDOWN:
     Result := True;  // ショートカットを無効にする
  CM_APPSYSCOMMAND:
     Result := True;  // アクセラレータを無効にする
  else
     Result := False;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.HookMainWindow(Hook);
end;
参照: [Delphi-ML:21685] <メニュー>

0027  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
アイコン状態で起動するアプリ

参照: [Delphi-ML:13173] [Delphi-ML:13185] <バグ>

0040  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
フォームの印刷時にComboBoxの内容が印刷されない

Delphi3 になって、フォームの印刷時に TComboBox の内容(テキスト)が印刷表示されなくなりました。
Delphi2 ではちゃんと印刷されます。

kohiroさんが[Delphi-ML:19070]で解法を示してくださっています。
参照: [Delphi-ML:19070] <印刷> <バグ> <Standard> <コンポーネント >

0020  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
設計時にフォームがエラーで読み込めず変更もできない

 > フォームのActiveControlプロパティにタブシードで
 > 隠れている(つまりアクティブシートでない)コントロール
 > にのせてあるものをせっていしてしまい、その後セーブ
 > はできたのですが、プロジェクトをロードすると以下のような
 > エラーがでて、フォームが二度と表示されなくなってしまいました。

.dfmファイルをDelphiのエディタに放り込んでみましょう。
もしくは[ファイルを開く]で.dfmファイルを読み込みます。
すると、.dfmファイルがテキストとして編集できますので、ActiveControlプロパティの設定部分を書き換えられます。
参照: [Delphi-ML:5705] <開発環境>

[新規作成] [最新の情報に更新]

How To
Lounge
KeyWords

Tips
Delphi
Home
Osamu Takeuchi osamu@big.or.jp