2

私が取り組んでいるアプリケーションの一部には、CMExit メッセージの受信時に検証を行うフォーム コントロールがあります。これはまさに Delphi のドキュメントに記載されている方法です (このコード サンプルは Delphi のヘルプ ファイルからのものです)。

procedure TDBCalendar.CMExit(var Message: TWMNoParams);
begin
 try
  FDataLink.UpdateRecord;                          { tell data link to update database }
 except
  on Exception do SetFocus;                      { if it failed, don't let focus leave }
 end;
 inherited;
end;

これの目的は、コントロールがフォーカスを失うとすぐに検証を実行することです。たとえば、[OK] ボタンをクリックすると、フォーム コントロールはフォーカスを失い、このメソッドが実行され、例外が発生すると、フォーカスがそのフォーム コントロールに戻されます。(したがって、[OK] ボタンの「クリック」イベントは通過せず、ダイアログは閉じません)。

私が抱えている問題は、このフォーム コントロールがモーダル ダイアログ ウィンドウ内にあることです。[OK] をクリックすると、実際に CMExit メッセージが送信され、レコードが更新されます (および検証が行われます)。ただし、フォーム コントロール内で Enter キーを押すと、CMExit メッセージを送信せずにモーダル ダイアログが閉じます。フォーム コントロールが「フォーカスを失う」ことがないかのようです。これは、フォームが実際にデータを検証せずにダイアログが閉じるだけでなく、データ セットも更新されないことを意味します。

この問題を考えると、データセットの更新/検証コードを配置するのに最適な場所はどこですか? これをダイアログ フォーム自体に移動して OnCloseQuery ハンドラーに実装することもできますが、これはフォーム コントロールフォーム自体の両方でロジックが重複することを意味します。(フォーム コントロールは他の場所で使用されているため、その動作を変更したくありません)。

(コントロールが実際にフォーカスを失うことはないため、CMExit はトリガーされないと推測します。フォームは閉じられますが、フォーム コントロールは閉じたフォームにまだ「フォーカスを持っています」。)

4

1 に答える 1

7

フォームを閉じても、TControl の終了時イベントが発生するとは限りません。たとえば、ユーザーは Alt-F4 を押すことができます。

検証を別の proc に移動し、その別の proc を終了時イベント終了時イベントの両方から呼び出すことをお勧めします。

以下のコードは、あまり変更しなくても機能するはずです。

function TDBCalendar.UpdateSuccessful: boolean;
begin
  { tell data link to update database }
  { if successful, return True, else return False }
  { this function must be Public if a form is gonna check this value }
  Result := True;
  try
    FDataLink.UpdateRecord;
  except on Exception do
    Result := False;
  end;
  inherited;
end;

procedure TDBCalendar.CMExit(var Message: TWMNoParams);
begin
  //if not valid, then don't let them leave
  if not(UpdateSuccessful) then begin
    SetFocus;
  end;
end;

///////////////////////////////////////////
//on the form that contains your control...
///////////////////////////////////////////

procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  //if not valid, then don't let them close the form
  if not(dbcal.ControlIsValid) then begin
    Action := caNone;
  end
  else begin
    inherited;
  end;
end;
于 2009-04-06T17:39:37.803 に答える