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

у меня есть два "modeless" формы работы:

  • один специальный mainform в
  • другой-это бесформенная форма

enter image description here

вы можете увидеть:

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

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

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

enter image description here

The модальные форма строится так:

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. По умолчанию диалоговое окно "прогресс"не имеет режима.

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

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

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

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

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

1 ответов


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

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

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

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

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

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

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

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

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

  • повторно включить владельца.
  • уничтожить модальный диалог.

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

отсутствие фликера. Нет интерлопер.