web-dev-qa-db-ja.com

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

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

[〜#〜]編集[〜#〜]

私はDelphi7を使用しています。

23
LukLed

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を使用してください。これにより、モーダルフォームで問題が発生した場合、作成フォームが常に再度有効になります。

24
Ken White

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

適切と思われる解決策を見つけました。 CreateParamsメソッドのDelphi2007のコードを参照しましたが、かなり一致しています(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のソリューションに近いようです。

6
Jim Gilmartin

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

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

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

2
Jim Gilmartin

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

1

onShowFormでお試しください:

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