Форма скрыта за другими формами при вызове ShowModal
Мое приложение основано на модальных формах. Основная форма открывает одну форму с помощью ShowModal, эта форма открывает другую форму с помощью ShowModal, поэтому мы сложили модальные формы. Иногда возникает проблема, заключающаяся в том, что когда мы вызываем ShowModal в новой форме, он скрывается за предыдущими формами, а не отображается сверху. После нажатия alt+tab форма возвращается наверх, но это не хорошее решение. Встречались ли вы с этой проблемой и как вы с ней справились?
РЕДАКТИРОВАТЬ:
Я использую Delphi 7.
6 ответов
Вы не упомянули, какая версия Delphi...
Более новые версии Delphi добавили два новых свойства в TCustomForm: PopupMode и PopupParent. Установка PopupParent вашего модального диалога в форму, которая создает это диалоговое окно, гарантирует, что дочерняя форма остается поверх своего родительского. Обычно это решает проблему, которую вы описываете.
Я думаю, что эта пара свойств была добавлена в Delphi 2006, но, возможно, это был 2005 год. Они определенно присутствуют в Delphi 2007 и выше.
РЕДАКТИРОВАТЬ: После того, как вы увидели, что вы используете 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) не помогает. Поскольку я не всегда могу воспроизвести эту проблему, я не могу сказать наверняка.
Я нашел решение, которое кажется подходящим. Я ссылался на код в Delphi 2007 для метода CreateParams, и он очень близко соответствует (без всего остального кода, который обрабатывает 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.
Из этой ссылки видно, что проблема связана с "окном Ghosting", появившимся в 2000/XP. Вы можете отключить функцию Ghosting, вызвав следующий код при запуске.
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
), Я обнаружил, что передача дескриптора вызывающего окна необходима для того, чтобы убедиться, что подсказка постоянно появляется сверху.