2

グリッド内編集で非モーダル フォームを使用する Delphi 6 アプリケーションがあります。FormClose イベント内で、エントリが正方形であることを確認し、そうでない場合は閉じないようにします。

ただし、ユーザーが背後のメイン フォームをクリックすると、元のフォームが背後に消えますが (ご想像のとおり)、ユーザーはグリッド内の変更が検証されずに、メイン画面の新しいレコードに移動できます。

FormDeactivate イベントを試してみました。これは発生しますが、非アクティブ化を防止するメカニズムがないようです (FormClose イベントの Action パラメーターとは異なります)。グリッドから OnExit を試しましたが、無効化しても起動しません。WM_ACTIVATE メッセージをトラップして Msg.Result = 1 を設定しようとしましたが、これは効果がありません (別の WM_ACTIVATE メッセージがメイン フォームに送信されている可能性があります)。

そのため、ユーザーが別のフォームをクリックしたときにフォームの非アクティブ化を (条件付きで) 防止する方法についてのアイデアを探しています。(PS フォーム スタイルを fsStayOnTop に変更したくありません)

ありがとう

4

6 に答える 6

2

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;

この回答は、フォームの非アクティブ化を防ぐために何もしないため、技術的にはあなたの質問に答えていないことを指摘する必要がありますが、実際に非アクティブ化を防ぐ他の回答を拒否しました。

于 2009-10-05T16:38:27.573 に答える
1

を呼び出すとShowModal、表示されているフォーム以外のすべてのフォームが無効になります。返品の直前に再度有効になりShowModalます。

編集フォームを非モーダルに表示し、データの編集が開始されたら、他のフォームを無効にしてフォーム自体をモーダルにします。編集が完了したら、他のフォームを有効にします。どうやら、ウィンドウを無効にすることは、常にEnabledプロパティを設定するほど簡単ではありません。を使用することをお勧めしますが、編集フォームを含むすべてのDisableTaskWindowsウィンドウが無効になります。それにもかかわらず、それがForms.pasでどのように実装されているかを見てください。無効にしたすべてのウィンドウのリストを保持するため、後でそれらだけが再度有効になります。

于 2009-10-05T15:22:34.670 に答える
0

Delphi 2006では、OnMouseActivateイベントが導入されました。メインフォームのOnMouseActivateを使用すると、他のフォームが表示されている場合にメインフォームがアクティブ化されないようにすることができます。

もちろん、これはD6では機能しません。

于 2009-10-05T12:09:23.453 に答える
0

ここで説明するように、ウィンドウにフォーカスが必要かどうかを追跡する状態をモデルに導入し、プログラムでフォーカスをグリッドウィンドウに戻す他のフォームでonFocusハンドラーを使用することもできます。

[編集]私のコメントのコピー:

フォームのonShowイベントにグリッドで登録できます。(実装する場合は、アプリケーションの現在のレイアウトに対するグリッドの依存関係を最小限に抑えるように、何らかの方法で構成可能にするようにしてください。フォームによって呼び出されるメソッドを提供することで、呼び出し元のフォームでグリッドのイベント登録をトリガーすることができます。 onShowイベントの場合)

イベント登録について詳しく説明するには:

プログラムでイベントハンドラーをアタッチできます。これについてはネット上にたくさんのハウツーがあります。ここで利用できるDelphiがないため、現在動作中のコードをコピーできません。

イベントをプログラムで添付するための擬似コード!

myform.onShow=myGrid.formOnShowHandler;

formOnShowHandlerには、IDEがonShowイベント用に生成する関数と同じ署名があります。これには、どのフォームがハンドラーを呼び出したかを把握するために使用できるパラメーターがあるため、関数を再利用して、フォームをバックグラウンドに配置し、グリッドフォーム(たとえばグリッドの親)を再度表示できます。

于 2009-10-05T11:23:25.883 に答える
0

みんなの助けと提案に感謝します。

これが私が行った解決策です:「グリッドフォーム」(例:Form2)...

public  
    PricesNotSquare: boolean;  

FormDeactivate イベントで、PricesNotSquare が一致しない場合は true に設定します。

メイン フォームの OnActivate イベントでは、...

  if Assigned(Form2) and (Form2.PricesNotSquare) then  
  begin  
      ShowMessage( 'Please ensure the total Prices match before leaving the form' );  
      Form2.Show;  
      exit;  
  end;  
  // other form activate stuff here  

簡単な解決策であることが判明しましたが、それを得るのに少し時間がかかりました。

うまくいきそうですが、問題がある場合は、メッセージを送信するというアイデアを取り入れます。

于 2009-10-06T10:28:37.187 に答える
0

役に立つ回答ではありませんが、これは正しいアプローチではないという他の回答者の意見に同意する必要があると思います。問題を解決するために立ち止まって別の方法を検討する方が良い場合があります。

必要なイベント/メソッド/メッセージを見つけることができたとしても、電気が消えるシナリオに対処できる必要があります。

もう少し有用なメモとして、準備が整うまでメインフォームを無効にしてみましたか? すべてのコントロールをパネルに配置してから実行できます

panel1.enabled := false;
于 2009-10-05T19:45:18.367 に答える