7

Delphi 2009 では、単純に次のようにします。

FindDialog.Execute;

FindDialog ウィンドウは、プログラムのメイン ウィンドウの上に表示されます。

ただし、自分のプログラムのウィンドウの上に他のプログラムから別のウィンドウを開くと、FindDialog ウィンドウが他のウィンドウの上に表示されたままになります。

別のプログラム (メモ帳など) の FindDialog でこれを試しても、これは起こりません。メモ帳とその FindDialog で別のプログラムのウィンドウを開くと、メモ帳と FindDialog の両方のウィンドウが表示されます。これは正しく、期待される動作のようです。

これは私が間違っていることですか、それとも Delphi が FindDialog を実装する方法に問題があるのでしょうか? メモ帳のように機能させるためにできることはありますか?


コメントありがとうございます。私の問題を再現できないという事実は、それが別の原因であるという手がかりです。これは私がそれを追跡するのに役立ちます。もう少し調べて、何かわかったらここに追加情報を投稿します。


とても興味深い。PrintDialog が一番上に表示されません。なぜ私のFindDialogがそうするのかはまだわかりません。まだまだ研究中…


呼び出しを次のように変更しました: FindDialog.Execute(Handle); まだ上です。


別の FindDialog (今回は FindDialog1) をメイン フォームに追加し、プログラムの起動時に実行します。トップに留まる動作は同じです。これは、少なくとも、FindDialog やそのために行ったカスタマイズとは何の関係もないことを示しています。したがって、それは私のメインフォームの設定でなければなりません。


これに遭遇したのは私だけではないようです。参照:リソース チューナー: Delphi アプリケーションのように見えるバージョン履歴。バージョン 1.99 では、次のように記載されています。私は彼らに連絡して、彼らが修正した内容を覚えているかどうかを確認するかもしれません.


フォームにいくつかの新しいダイアログを追加し、これらの呼び出しを 1 か所に配置します。

FindDialog1.Execute();
PrintDialog1.Execute();
ReplaceDialog1.Execute();
FontDialog1.Execute();

FindDialog と ReplaceDialog は、他のウィンドウの前面に表示されます。PrintDialog と FontDialog が最上位に留まらず、正常に機能しません。

では、最初の 2 つのダイアログが間違っている原因となっている 2 つのダイアログ セットの違いは何でしょうか?


また、この問題は、Delphi 4 でコンパイルされた私のプログラムの古いバージョンでも発生します。Delphi 4 を使用していた古いバージョンでは、この問題は発生しなかったことがわかりました。

そして、この問題を報告したのはユーザーでした。彼は Windows XP を使用しており、私は Vista で開発しているため、異なる OS で発生します。


確認: はい、新しいフォームを作成し、そこに FindDialog を追加します。FindDialog には問題はありません。これは、私のプログラムの何かが FindDialog を一番上に置いていることを示しています。さて、私はそれが何であるかを知る必要があります。他にアイデアはありますか?誰かが私にこれを解決する手がかりさえ与えてくれる答えをくれたら、彼らは受け入れられた答えを得るでしょう.


解決策: Sertac の回答に対する編集により、回避策が得られました。

  Application.NormalizeTopMosts;
  FindDialog.Execute();
  Application.RestoreTopMosts;

これを行うと、アプリケーションが TopMost でない場合に FindDialog が TopMost になるのを防ぎます。

... しかし、これ (NormalizeTopMosts の Delphi ヘルプ) は非常に紛らわしく、これを行う必要があることを示していません。

この「修正」が他の問題を引き起こさないことを願っています。

4

1 に答える 1

3

VCL コードを見ると、検索ダイアログ ボックスが最前面に表示される唯一の方法は、'Execute' が呼び出されたときに既に最上位のウィンドウが存在することです。これはコーディング方法であり、ダイアログは、アプリケーションの z オーダーで一番上のウィンドウが所有する 'TRedirectorWindow' によって所有されます。この「最上位ウィンドウ」が最上位ウィンドウである場合、検索ダイアログも最上位ウィンドウです。

procedure TForm1.Button1Click(Sender: TObject);
var
  f: TForm;
begin
  f := TForm.CreateNew(Self);
  f.FormStyle := fsStayOnTop;
  f.Show;
  FindDialog1.Execute;
end;

また、

procedure TForm1.Button1Click(Sender: TObject);
begin
  FormStyle := fsStayOnTop;
  FindDialog1.Execute;
  FormStyle := fsNormal;
end;


上記のサンプルは、最上位の検索ダイアログを作成します。しかし、ステイオントップフォームは見過ごされない可能性があるので、これが問題の原因ではないと思います.

いずれにせよ、それはそれであるか、他のコードによってダイアログのスタイルを何らかの形で変更しています。


ところで、さまざまなハンドルを に渡すテストを気にしないFindDialog1.Execute()でください。効果はありません。質問に対する私のコメントを参照してください。

編集:

これはどう:

procedure TForm1.Button4Click(Sender: TObject);
var
  f: TForm;
begin
  f := TForm.CreateNew(Self);
  f.FormStyle := fsStayOnTop;
  f.Show;
  f.Hide;
  FindDialog1.Execute;
end;

要点は、によって列挙されるためにウィンドウが表示されている必要はないということEnumThreadWindowsです。そのため、既存の最前面に表示されるフォームによって、検索ダイアログがこの動作を示す可能性があります。

推測するよりも、テストして見てください。検索ダイアログを起動する直前に、以下のテストを実行します。これには、「dialogs.pas」がダイアログのベースを見つけるために実行するロジックが組み込まれており、ダイアログが最上位になる場合は例外が発生します。

function EnumThreadWndProc(hwnd: HWND; var lParam: LPARAM): Bool; stdcall;
var
  Window: TWinControl;
begin
  Result := True;
  Window := FindControl(hwnd);
  if Assigned(Window) and (Window is TForm) then begin
    Result := False;
    lParam := Longint(Window);
  end;
end;

procedure TForm1.Button6Click(Sender: TObject);
var
  OnTopForm: Longint;
begin
  OnTopForm := 0;
  EnumThreadWindows(GetCurrentThreadId, @EnumThreadWndProc, LPARAM(@OnTopForm));
//  if (OnTopForm <> 0) and (TForm(OnTopForm).FormStyle = fsStayOnTop) then
  if (OnTopForm <> 0) and (GetWindowLong(TForm(OnTopForm).Handle,
                            GWL_EXSTYLE) and WS_EX_TOPMOST = WS_EX_TOPMOST) then
    raise Exception.Create('darn! got one: ' + TForm(OnTopForm).Name);
end;


もう 1 つのテストは、ダイアログを起動する前にアプリケーションを呼び出すことNormalizeTopMostsです。ただし、Delphi の一部のバージョンでは、このメソッドが壊れていて機能しないことがわかっています。

于 2011-03-22T02:00:16.843 に答える