Как я могу не дать FindDialog оставаться на вершине (Delphi)?
В Delphi 2009 я делаю простое:
FindDialog.Execute;
Окно FindDialog остается поверх главного окна моей программы, как и должно быть.
Однако, если я открою другое окно из какой-либо другой программы поверх окна моей собственной программы, окно FindDialog останется поверх другого окна.
Если я попробую это с FindDialog из другой программы (например, Блокнот), это не произойдет. Открытие другого окна программы через Блокнот и его FindDialog покроет оба окна: Блокнот и FindDialog. Кажется, это правильное и ожидаемое поведение.
Это то, что я делаю неправильно, или это проблема с тем, как Delphi реализовал FindDialog? Есть ли что-то, что я могу сделать, чтобы это работало в блокноте?
Спасибо всем за комментарии. Тот факт, что вы не можете воспроизвести мою проблему, уже указывает на то, что это вызвано чем-то другим. Это поможет мне отследить это. Я исследую немного больше и опубликую дополнительную информацию здесь, когда узнаю что-то.
Очень интересно. Мой PrintDialog не остается на вершине. До сих пор не знаю, почему мой FindDialog делает. Все еще исследую...
Я изменил вызов на: FindDialog.Execute(Handle); Все еще на вершине.
Я добавил еще один FindDialog (на этот раз FindDialog1) в свою основную форму и запускаю ее при запуске моей программы. У него такое же поведение "остаться на вершине". Это по крайней мере означает, что это не имеет ничего общего с моим FindDialog или настройками, которые я сделал с ним. Так что это должна быть настройка в моей основной форме.
Не похоже, что я единственный, кто столкнулся с этим. См. Ресурсный тюнер: История версий, которая выглядит как приложение 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 ответ
Глядя на код 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()
, это не будет иметь эффекта, смотрите мой комментарий к вашему вопросу.
редактировать:
Как насчет этого:
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 этот метод не работает и не выполняет свою работу.