Delphi - Как предотвратить перемещение Forms / MsgBoxes по предыдущей форме? - PullRequest
15 голосов
/ 08 июня 2010

Много раз после эры Windows 98 мы сталкивались с тем, что некоторые диалоги теряют Z-порядок и возвращаются к предыдущей форме.

Например:

Dialog1.ShowModal;

Dialog1.OnClickButton() : ShowMessage('anything');

Когда появляется MessageBox, он иногда не имеет фокуса и перемещается под Dialog1. Пользователи смущены этим, они говорят: мое приложение замерзло !!! Но если они используют Alt + Tab для перехода в другое приложение и обратно, фокус возвращается к MessageBox, и это будет окно переднего плана.

Мы испытали это с ShowMessage, MessageBox, обычными формами, а также с формами QuickReport.

Кто-нибудь знает об этом? Это ошибка Windows? Как вы можете предотвратить это? Как это поймать?

Спасибо за вашу помощь: дд


Я действительно сказал, что ПОСЛЕ Win98, поэтому эта проблема затрагивает все ОС (в том числе и Win7). Мы использовали Delphi 6 Prof, поэтому свойства не работают с формами по умолчанию.

Кто-то сказал, что диалоги сообщений можно контролировать с помощью MessageBox + MB_APPLMODAL. Это хорошая новость, но у нас есть много старых форм и компонентов, сторонних инструментов.

Так что трудно сделать совершенно новое приложение с подменой форм.

Но мы попробуем это сделать.

Я думаю, что ответ - это половина проблемы приложения и половина проблемы Windows. Если Windows иногда это обрабатывает, а иногда нет - это, похоже, ошибка Windows. Но если мы можем заставить хорошее модальное создание окна, то это программная ошибка.

Может кто-нибудь объяснить мне, что означает флаг WS_POPUP? Есть ли у него побочный эффект или нет?

спасибо: дд

Ответы [ 4 ]

15 голосов
/ 08 июня 2010

Для этого предназначены свойства PopupMode и PopupParent .

Например, вы можете сделать:

Dialog1.PopupMode := pmExplicit;
Dialog1.PopupParent := self;
Dialog1.ShowModal;

Это сообщает Windows правильный Z-порядок.

6 голосов
/ 08 июня 2010

Для старых версий Delphi (до Delphi 2007) в формах, ДРУГИХ, чем ваша основная форма:

interface
  TMyForm = Class(TForm)
  protected
    procedure CreateParams(var Para: TCreateParams); override;
  end;
...
implementation
...
procedure TMyForm.CreateParams(var Para: TCreateParams);
begin
  inherited;
  Para.Style := Para.Style or WS_POPUP;
  { WinXP Window manager requires this for proper Z-Ordering }
  // Para.WndParent:=GetActiveWindow;
  Para.WndParent := Application.MainForm.Handle;
end;

Для окон сообщения включите MB_TOPMOST в свои флаги:

Application.MessageBox(PChar(amessage), PChar(atitle),    otherflags or MB_TOPMOST);
0 голосов
/ 31 августа 2011

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

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
  WS_EX_APPWINDOW or WS_EX_TOPMOST);
SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopWindow);

Ручка - это ручка формы (Form1.Handle). Часть WS_EX_APPWINDOW заставляет каждое окно появляться на панели задач, удалите его, если вы не хотите, чтобы этот дополнительный эффект.

Для основной формы я использую эту строку:

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or
  WS_EX_TOPMOST);

Я также использую эту функцию, чтобы помочь создавать свои собственные диалоги (я создал новую функцию для каждого стиля диалога - ошибка, подтверждение и т. Д.):

function CustomDlg(const AMessage : string; const ADlgType: TMsgDlgType;
  const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn) : TForm;
begin
  Result := CreateMessageDialog(AMessage, ADlgType, AButtons, ADefaultButton);
  with Result do
    begin
      SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
        WS_EX_APPWINDOW or WS_EX_TOPMOST);
      SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopwindow);
      FormStyle := fsStayOnTop;
      BringToFront;
    end;
end;

Часть FormStyle := fsStayOnTop;, конечно, необязательна, но я использую ее, чтобы мои диалоги подтверждения и ошибок всегда были видны пользователю.

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

0 голосов
/ 09 июня 2010

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

Прежде всего, я хотел бы прояснить, что постер, ИМХО, не использует Windows 98. Он пишет «после эпохи Windows 98», что, как я понимаю, означает, что у него эта проблема с версиями Windows после 98.

Поскольку у меня тоже есть эта проблема (CB2009), я хотел бы подчеркнуть вопрос автора «Это ошибка Windows?», На который я не видел ответа. Если это ошибка Delphi / Builder, может быть, есть способ ее избежать? Я не вижу, как перехват всех возможных диалогов является работоспособным решением, и не избегаю использования fsStayOnTop. У меня есть форма настроек, которая должна оставаться поверх моей основной формы, но форма настроек может и будет отображать диалоговые окна, которые при определенных условиях исчезают при форме настроек.

Было бы очень полезно, если бы я понял, где поддержка z-порядка идет не так, как надо, поскольку это может дать подсказку, как этого избежать.

...