Как показать модальное диалоговое окно из немодальной формы?

У меня есть две "немодальные" формы:

  • Одним из них является специальная MainForm
  • другая немодальная форма

введите описание изображения здесь

Ты можешь видеть:

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

Теперь покажите модальную форму

Из этой немодальной формы я хочу показать модальную:

введите описание изображения здесь

Модальная форма строится как:

var
    frmExchangeConfirm: TfrmExchangeConfirm;
begin
    frmExchangeConfirm := TfrmExchangeConfirm.Create(Application);
    try
        //Setting popupMode and popupParent still makes the MainForm disabled
//      frmExchangeConfirm.PopupMode := pmExplicit;
//      frmExchangeConfirm.PopupParent := Self; //owned by us

        frmExchangeConfirm.OwnerForm := Self; //tell the form which owner to use
        frmExchangeConfirm.ShowModal;
    finally
        frmExchangeConfirm.Free;
    end;

Модальная форма сообщает, какого владельца использовать через новый OwnerForm имущество:

protected
   procedure SetOwnerForm(const Value: TForm);
public
   property OwnerForm: TForm read GetOwnerForm write SetOwnerForm;
end;

который заставляет ручку отдыха:

procedure TfrmExchangeConfirm.SetOwnerForm(const Value: TForm);
begin
    FOwnerForm := Value;

    if Self.HandleAllocated then
        Self.RecreateWnd;
end;

и тогда второй раз через CreateParams:

procedure TfrmExchangeConfirm.CreateParams(var Params: TCreateParams);
begin
    inherited;

    if FOwnerForm <> nil then
        Params.WndParent := FOwnerForm.Handle;
end;

Проблема в:

  • как только эта принадлежащая модальная форма показана, я не могу взаимодействовать с MainForm
  • я не могу свернуть MainForm, используя кнопку на панели задач
  • я не могу свернуть модал или его родителя, используя кнопку на панели задач
  • если я сверну модальную форму с помощью кнопки " Свернуть", MainForm исчезнет
  • я могу активировать MainForm, используя кнопку на панели задач; но я не могу с этим взаимодействовать

Я задавал этот вопрос около 7 раз за последнее десятилетие. В прошлый раз мне обещали, что создание главной формы MainForm решит все проблемы.

Бонус: WinForms обрабатывает это правильно, начиная с.NET 1.0.

Существует много путаницы в том, что такое модальный диалог. Диалог является модальным, когда вы должны взаимодействовать с ним, прежде чем вы сможете продолжать использовать его владельца. Из Руководства по проектированию интерфейса Windows:

Диалоговые окна имеют два основных типа:

  • Модальные диалоговые окна требуют от пользователей завершения и закрытия, прежде чем продолжить работу с окном владельца. Эти диалоговые окна лучше всего использовать для критических или нечастых, одноразовых задач, которые требуют продолжения перед продолжением.
  • Немодальные диалоговые окна позволяют пользователям по желанию переключаться между диалоговым окном и окном владельца. Эти диалоговые окна лучше всего использовать для частых, повторяющихся текущих задач.

У Windows есть понятие "владелец". Когда окно "принадлежит", оно всегда будет отображаться поверх его владельца. Когда окно является "модальным", это означает, что владелец отключен, пока модальное задание не будет завершено.

Вы можете увидеть этот эффект в ProgressDialog API:

HRESULT StartProgressDialog(
  [in] HWND     hwndParent,
       IUnknown *punkEnableModless,
       DWORD    dwFlags,
       LPCVOID  pvReserved
);

hwndParent [in]
Тип: HWND
Дескриптор родительского окна диалогового окна.

dwFlags
Тип: DWORD
PROGDLG_MODAL
Диалоговое окно хода выполнения будет модальным окну, указанному в hwndParent. По умолчанию диалоговое окно хода выполнения является немодальным.

Конечно, вы можете иметь в виду, и отключить все другие окна

  • в теме
  • процесс
  • или система

Но я хочу иметь правильное поведение. Я хочу делать:

  • что делает винда
  • что делают приложения Office
  • что делает Beyond Compare
  • что делает WinForms
  • что делает WPF
  • что делает каждое приложение, которое я когда-либо использовал
  • и что будет ожидать любой пользователь

Я хотел этого в моих приложениях Delphi с 1998 года; когда понял, Delphi 3 не поддерживает должным образом Windows 95 и панель задач.

1 ответ

Решение

ShowModal отключает все другие окна верхнего уровня в том же потоке. Это включает в себя вашу основную форму.

Вам нужно будет уточнить эту форму, чтобы она велась так, как вы хотите. Сделайте следующее:

  1. Отключить форму немодального владельца.
  2. Покажите "модальную" форму, позвонив Show,
  3. Когда "модальная" форма закрыта, включите немодального владельца. Убедитесь, что владелец включен, прежде чем окно "модальной" формы будет уничтожено, как описано ниже.

Вы можете запустить свой собственный модальный цикл сообщений между шагами 2 и 3, как ShowModal делает, но это может быть излишним. Я бы просто показал форму немодальной, но отключил бы ее владельца, чтобы сделать ее "модальной" по отношению к этому владельцу.

Этот процесс немного деликатный. Посмотрите на источник ShowModal для вдохновения. Кроме того, эпическая серия статей Рэймонда о модальности является важным чтением. Я ссылаюсь на все это здесь: почему MessageBox не блокирует приложение в синхронизированном потоке?

И даже больше от Раймонда: правильный порядок отключения и включения окон:

Когда вы уничтожаете модальный диалог, вы уничтожаете окно с активацией переднего плана. Менеджеру окон теперь нужно найти кого-то, кто может активировать. Он пытается передать его владельцу диалога, но владелец все еще отключен, поэтому диспетчер окон пропускает его и ищет другое окно, которое не отключено.

Вот почему вы получаете странное окно-нарушитель.

Правильный порядок уничтожения модального диалога

  • Повторно включите владельца.
  • Разрушить модальный диалог.

На этот раз, когда модальное диалоговое окно уничтожено, диспетчер окон смотрит на владельца и на этот раз он включен, поэтому он наследует активацию.

Нет мерцания. Нет нарушителя.

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