Как я могу не дать FindDialog оставаться на вершине (Delphi)? - PullRequest
6 голосов
/ 21 марта 2011

В Delphi 2009 я делаю простое:

FindDialog.Execute;

Окно FindDialog остается поверх главного окна моей программы, как и должно быть.

Однако, если я открою другое окно изв другой программе, поверх окна моей собственной программы, окно FindDialog остается поверх другого окна.

Если я попробую это с FindDialog из другой программы (например, Блокнота), этого не произойдет.Открытие окна другой программы через Блокнот и его FindDialog покроет оба окна: Блокнот и FindDialog.Кажется, это правильное и ожидаемое поведение.

Я что-то не так делаю или это проблема с тем, как Delphi реализовал FindDialog?Есть ли что-то, что я могу сделать, чтобы заставить его работать в блокноте?


Спасибо всем за комментарии.Тот факт, что вы не можете воспроизвести мою проблему, уже указывает на то, что это вызвано чем-то другим.Это поможет мне отследить это.Я исследую немного больше и опубликую дополнительную информацию здесь, когда узнаю что-нибудь.


Очень интересно.Мой PrintDialog не остается на вершине.До сих пор не знаю, почему мой FindDialog делает.Все еще исследую ...


Я изменил вызов на: FindDialog.Execute (Handle);По-прежнему на вершине.


Я добавил еще один FindDialog (на этот раз FindDialog1) в свою основную форму, и я запускаю его при запуске моей программы.У него такое же поведение "остаться на вершине".Это по крайней мере означает, что это не имеет ничего общего с моим FindDialog или настройками, которые я сделал с ним.Таким образом, это должно быть урегулирование в моей основной форме.


Не похоже, что я единственный, кто столкнулся с этим.См .: Resource Tuner: история версий , которая выглядит как приложение Delphi, где в версии 1.99 говорится: «Исправление: окно предварительного просмотра (поиска) диалогового окна оставалось сверху при переключении на другое приложение».Я мог бы попытаться связаться с ними и посмотреть, помнят ли они, каково было их исправление.


Я добавляю несколько новых диалоговых окон в форму и помещаю эти вызовы в одном месте:

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

FindDialog и ReplaceDialog остаются поверх других окон.PrintDialog и FontDialog не остаются на вершине и работают должным образом.

Так что же отличается между двумя наборами диалогов, которые заставляют первые два делать это неправильно?


Кроме того, эта проблема возникает в старой версии моей программы, которая была скомпилирована с Delphi 4. Упс.Теперь я вижу, что этой проблемы не было в моей старой версии, которая использовала Delphi 4.

И это был пользователь, который сообщил об этой проблеме.Он использует Windows XP, а я занимаюсь разработкой под Vista, поэтому это происходит под разными ОС.


Подтверждение: Да, я создаю новую форму и добавляю в нее FindDialog.FindDialog не имеет проблемы.Это означает, что что-то в моей программе заставляет FindDialog оставаться на вершине.Теперь я просто должен выяснить, что это такое.Есть еще идеи?Если кто-то даст мне ответ, который даже даст мне подсказку, чтобы помочь мне решить эту проблему, то он получит принятый ответ.


Решение: редактирование Sertac его ответа дало мне обходной путь:

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

Это не позволяет FindDialog быть TopMost, когда приложение не является TopMost.

... Но я все еще действительно не понимаю этого (справка Delphi по NormalizeTopMosts) очень запутаннаяи не означает, что он должен это делать.

Надеюсь, это "исправление" не вызовет других проблем.

1 Ответ

3 голосов
/ 22 марта 2011

Глядя на код VCL, единственный возможный способ, которым диалоговое окно поиска остается сверху, - это уже самое верхнее окно, когда вызывается «Выполнить».Вот как это закодировано, диалоговое окно становится владельцем «TRedirectorWindow», которое становится владельцем верхнего окна в z-порядке в приложении.Если это «верхнее окно» является самым верхним окном, тогда диалоговое окно поиска также имеет вид.

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(), это не даст никакого эффекта, см. Мой комментарий к вашему вопросу.

edit:

Howпо этому поводу:

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;

Еще одним тестом может быть вызов NormalizeTopMosts приложения перед запуском диалога, но я знаю, что с некоторыми версиями Delphi этот метод не работает и не выполняет свою работу.

...