ShowModalが呼び出されると、フォームは他のフォームの後ろに隠れます

StackOverflow https://stackoverflow.com/questions/1639125

  •  08-07-2019
  •  | 
  •  

質問

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

編集

Delphi 7を使用しています。

役に立ちましたか?

解決

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

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

このプロパティのペアはDelphi 2006で追加されたと思いますが、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を使用することを確認してください。そうすれば、モーダルフォームで何か問題が発生した場合、作成フォームが常に再度有効になります。

他のヒント

別の回答を追加して申し訳ありませんが、もう少し調査を行ったところ、以前の回答(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のソリューションに近いようです。

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

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

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

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

試してみる OnShowForm:

PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);

「常に手前に表示」を使用すると、複数のフォームにフラグを付けると、Zオーダーに問題が発生します。また、 も必要になる場合があります。 BringWindowToTop 関数。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top