Форма скрыта за другими формами при вызове 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), Я обнаружил, что передача дескриптора вызывающего окна необходима для того, чтобы убедиться, что подсказка постоянно появляется сверху.

Другие вопросы по тегам