30

私のアプリケーションはモーダル フォームに基づいています。メイン フォームは ShowModal で 1 つのフォームを開き、このフォームは ShowModal で別のフォームを開くため、モーダル フォームがスタックされています。新しいフォームで ShowModal を呼び出すと、前のフォームの上に表示されるのではなく、後ろに隠れてしまうという問題が時々あります。alt+tab を押した後、フォームはトップに戻りますが、これは良い解決策ではありません。この問題に遭遇しましたか? また、どのように対処しましたか?

編集

Delphi7を使用しています。

4

6 に答える 6

26

Delphiのどのバージョンについては言及していません...

新しいDelphiバージョンでは、TCustomFormにPopupModeとPopupParentの2つの新しいプロパティが追加されています。モーダルダイアログのPopupParentを、そのダイアログを作成しているフォームに設定すると、子フォームがその親の上にとどまるようになります。通常、説明している問題を修正します。

このプロパティのペアはDelphi2006で追加されたと思いますが、2005年であった可能性があります。Delphi2007以降では間違いなく存在します。

編集:Delphi 7を使用していることを確認した後、私が持っている唯一の提案は、モーダルフォームを表示するコードで、フォームの作成を無効にし、戻ったときに再度有効にすることです。これにより、作成ウィンドウが入力を受け取らないようにする必要があります。これにより、Zオーダーを正しく保つことができます。

このようなものが機能する可能性があります(D7を使用しなくなったため、テストされていません)。

procedure TForm1.ShowForm2;
begin
  Self.Enabled := False;
  try
    with TForm2.Create(nil) do
    begin
      try
        if ShowModal = mrOk then
          // Returned OK. Do something;
      finally
        Free;
      end;
    end;
  finally
    Self.Enabled := True;
  end;
end;

Form2がモーダルウィンドウを作成する場合(前述のとおり)、プロセスを繰り返します。Form2を無効にし、Form3を作成してモーダルで表示し、戻ってきたらForm2を再度有効にします。私が示したように、必ずtry..finallyを使用してください。これにより、モーダルフォームで問題が発生した場合に、作成フォームが常に再度有効になります。

于 2009-10-28T19:02:19.433 に答える
8

別の回答を追加して申し訳ありませんが、もう少し調査を行ったところ、以前の回答 (DisableProcessWindowsGhosting) が役に立たないことが示されています。この問題を常に再現できるとは限らないため、確実なことは言えません。

適切と思われる解決策を見つけました。CreateParams メソッドについて Delphi 2007 のコードを参照しましたが、これは非常によく一致します (PopupMode を処理する他のすべてのコードはありません)。

サブクラスの下にユニットを作成しましたTForm

unit uModalForms;

interface

uses Forms, Controls, Windows;
type
  TModalForm = class(TForm)
  protected
    procedure CreateParams(var params: TCreateParams); override;
  end;

implementation

procedure TModalForm.CreateParams(var params: TCreateParams);
begin
  inherited;

  params.WndParent := Screen.ActiveForm.Handle;

  if (params.WndParent <> 0) and (IsIconic(params.WndParent)
    or not IsWindowVisible(params.WndParent)
    or not IsWindowEnabled(params.WndParent)) then
    params.WndParent := 0;

  if params.WndParent = 0 then
    params.WndParent := Application.Handle;
end;

次に、このユニットをフォーム ユニットに含め、フォームのクラス (.pas コード ファイル内) を からclass(TForm)に変更します。class(TModalForm)

それは私にとってはうまくいき、CodeGearのソリューションに近いようです。

于 2009-11-19T19:37:07.757 に答える
2

このリンクから、問題は 2000/XP で導入された「ゴースト ウィンドウ」にあるようです。起動時に次のコードを呼び出すことで、ゴースト機能を無効にすることができます。

procedure DisableProcessWindowsGhosting;
var
  DisableProcessWindowsGhostingProc: procedure;
begin
  DisableProcessWindowsGhostingProc := GetProcAddress(
    GetModuleHandle('user32.dll'),
    'DisableProcessWindowsGhosting');
  if Assigned(DisableProcessWindowsGhostingProc) then
    DisableProcessWindowsGhostingProc;
end; 

私が確認できる唯一の問題は、ユーザーが応答していないアプリケーションのメイン ウィンドウを最小化、移動、または閉じることができる機能で問題が発生することです。Self.Enabled := Falseただし、この方法では、各呼び出しをコードでカバーする必要はありません。

于 2009-11-18T19:07:33.573 に答える
1

Visibleモーダルで開きたいフォームのプロパティを に設定するだけですFalse。次に、で開くことができ、.ShowModal();動作します。

于 2010-10-20T09:40:21.267 に答える
0

OnShowForm を試してください:

PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);
于 2015-07-08T06:45:55.903 に答える
0

複数のフォームで「Always On Top」フラグを使用すると、Z オーダーで問題が発生することがわかりました。また、その機能の必要性を見つけることもできますBringWindowToTop

組み込みの WinAPI ( MessageBox) を使用してメッセージ ボックスを起動するとき、プロンプトが常に一番上に表示されるようにするために、呼び出し元のウィンドウのハンドルを渡す必要があることがわかりました。

于 2009-10-28T18:50:13.120 に答える