Форма скрыта за другими формами, когда вызывается ShowModal - PullRequest
23 голосов
/ 28 октября 2009

Мое приложение основано на модальных формах. Основная форма открывает одну форму с помощью ShowModal, эта форма открывает другую форму с помощью ShowModal, поэтому мы сложили модальные формы. Иногда возникает проблема, заключающаяся в том, что когда мы вызываем ShowModal в новой форме, он скрывается за предыдущими формами, а не отображается сверху. После нажатия alt + tab форма возвращается наверх, но это не очень хорошее решение. Вы сталкивались с этой проблемой и как справились с ней?

EDIT

Я использую Delphi 7.

Ответы [ 6 ]

24 голосов
/ 28 октября 2009

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

6 голосов
/ 19 ноября 2009

Извините за добавление отдельного ответа, но я провел немного больше исследований, и некоторые из них указывают, что мой предыдущий ответ (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.

2 голосов
/ 18 ноября 2009

Из этой ссылки видно, что проблема связана с "окном Ghosting", появившимся в 2000 / XP. Вы можете отключить функцию ореола, вызывая следующий код при запуске.

procedure DisableProcessWindowsGhosting;
var
  DisableProcessWindowsGhostingProc: procedure;
begin
  DisableProcessWindowsGhostingProc := GetProcAddress(
    GetModuleHandle('user32.dll'),
    'DisableProcessWindowsGhosting');
  if Assigned(DisableProcessWindowsGhostingProc) then
    DisableProcessWindowsGhostingProc;
end; 

Единственная проблема, которую я вижу, состоит в том, что это вызовет проблемы с функцией, которая позволяет пользователю свернуть, переместить или закрыть главное окно приложения, которое не отвечает . Но при этом вам не нужно покрывать каждый звонок кодом Self.Enabled := False.

1 голос
/ 20 октября 2010

Просто установите для свойства Visible формы, которую вы хотите открыть модально, значение False. Затем вы можете открыть его с помощью .ShowModal();, и он будет работать.

0 голосов
/ 08 июля 2015

попробуй OnShowForm:

PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);
0 голосов
/ 28 октября 2009

Я обнаружил, что использование флага «Всегда сверху» в нескольких формах вызывает проблемы с Z-порядком. И вы также можете найти необходимость в функции BringWindowToTop.

При запуске окна сообщения с использованием встроенного WinAPI (MessageBox) я обнаружил, что передача дескриптора вызывающего окна необходима для того, чтобы убедиться, что приглашение все время появляется сверху.

...