Form表示後に処理を行う
33 FormShowAfterEvent 動作確認 Delphi2007 更新日 2008/01/16(水)
2010/07/06(火)

FormShow イベントでコンポーネントの表示関係の操作を行うと

> ---------------------------
> OnShow/OnHide イベントの処理中は表示状態の変更はできません.
> ---------------------------
> OK
> ---------------------------

このようなメッセージが表示されて動作がうまくいかない場合があります。
FormCreate イベントの場合でも困る時もあります。

そこで、FormShow 後にFormが表示されてから処理を行いましょう。

主に知られている次の2つのやり方があります。

1、CM_SHOWINGCHANGEDメッセージを使う。
2、独自のメッセージ定義してFormCreateやFormShowイベント内でPostMessageする。

以前は2のやり方をテクニックとして公開していましたが、
1のやり方の方が効率よさそうなので記述しておきます。
2のやり方もコードを乗せておきます。

どちらのやり方でもメッセージハンドラを定義している例ですが
ApplicationEventsのOnMessageイベントを使って
メッセージを受け取る実装も可能です。

◆CM_SHOWINGCHANGEDメッセージを使う。
────────────────────
type
  TForm1 = class(TForm)
  …
  private
    procedure CMShowingChanged(var Msg:TMessage);message CM_SHOWINGCHANGED;
  end;

procedure TForm1.MemoLogWrite(LogText: String);
begin
  Memo1.Lines.Add(
    Format('%s:%s', [
      FormatDateTime('yyyy/mm/dd hh:nn:ss', Now),
      LogText]) );
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  MemoLogWrite('FormShowEvent');
end;

procedure TForm1.CMShowingChanged(var Msg: TMessage);
begin
  inherited;

  if Visible = False then Exit;
  Self.Update; //更新を行っておく

  //処理を記述

  MemoLogWrite('CMShowingChanged');
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer1.Interval := 5000;
  Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Self.Visible := not Self.Visible;
end;

────────────────────
このようにしておくと、
	FormShowEvent
	CMShowingChanged
の順番でログが記述されます。

上記のコードのタイマーイベントで設定しているように
CMShowingChanged イベントは表示状態がON/OFFされる時に発生するため
Visible = False になる際にも呼び出されるので
イベント内で
	if Visible = False then Exit;
としています。


◆独自のメッセージ定義してPostMessageする。
次のコードで実現できます。
────────────────────
const   WM_ShowWaitEvent=WM_USER+$100;

type
  TForm1 = class(TForm)
  …
  private
    procedure WMShowWaitEvent(var Msg: TMessage); message WM_ShowWaitEvent;
  end;

procedure TForm1.FormShow(Sender: TObject);
begin
  MemoLogWrite('FormShowEvent');

  PostMessage(Self.Handle,WM_ShowWaitEvent, 0, 0);
end;

procedure TForm1.WMShowWaitEvent(var Msg: TMessage);
begin
  //処理を記述

  MemoLogWrite('WMShowWaitEvent');
end;
────────────────────
これも
	FormShowEvent
	WMShowWaitEvent
の順番でログが記述されます。



参考────────────────────
Delphi壁の穴 - [1.Delphiを覗く]
http://delfusa.main.jp/delfusafloor/archive/VA009712_take/delphi/kabedel.htm

[Delphi] フォームが表示し終えたとき - くろねこ研究所
http://www.blackcatlab.com/article.php/ProgramingFAQ_del0049

[Delphi Memo] Shimosoft
http://www12.plala.or.jp/selen/Delphi/

Delphi Tips
http://www.occn.zaq.ne.jp/maekawa/delphitip/index.html