Windows の従来のルールでは、フォーカス変更イベント中にフォーカスを変更することはできません。イベントはOnDeactivate
、フォーカス変更イベント中に発生します。あなたのフォームは非アクティブ化されていると言われています — OS は許可を求めていません — 同時に、他のフォームはアクティブ化されていると言われています。どちらのウィンドウもこの件に関して発言権はありません。これらのイベントの進行中にフォーカスを変更しようとすると、すべてのウィンドウが混乱するだけです。症状としては、2 つのウィンドウがフォーカスを持っているかのように自分自身をペイントする、入力カーソルが点滅しているにもかかわらずキーボード メッセージがどこにも行かない、などがあります。MSDNはさらに悲惨ですが、私はこれほどひどいものを目にしたことはありません。
このメッセージ [ WM_KILLFOCUS ] の処理中は、ウィンドウを表示またはアクティブ化する関数呼び出しを行わないでください。これにより、スレッドが制御を譲り、アプリケーションがメッセージへの応答を停止する可能性があります。詳細については、メッセージのデッドロックを参照してください。
フォーカス変更が開始された後はそれを否定することはできないため、事態が落ち着くまでイベントの処理を遅らせる必要があります。編集フォームが無効になり、そのデータがまだ有効になっていない場合は、フォームにメッセージを投稿してください。Posting はメッセージをメッセージ キューの最後に置くため、以前のすべてのメッセージ (特にフォーカス変更通知) が処理されるまで処理されません。メッセージが届いたら、データが無効であることを示し、フォーカスを編集フォームに戻します。
const
efm_InvalidData = wm_User + 1;
type
TEditForm = class(TForm)
...
private
procedure EFMInvalidData(var Msg: TMessage); message efm_InvalidData;
end;
procedure TEditForm.FormDeactivate(Sender: TObject);
begin
if DataNotValid then
PostMessage(Handle, efm_InvalidData, 0, 0);
end;
procedure TEditForm.EFMInvalidData(var Msg: TMessage);
begin
Self.SetFocus;
ShowMessage('Invalid data');
end;
この回答は、フォームの非アクティブ化を防ぐために何もしないため、技術的にはあなたの質問に答えていないことを指摘する必要がありますが、実際に非アクティブ化を防ぐ他の回答を拒否しました。