Delphi - Как предотвратить перемещение Forms/MsgBoxes по предыдущей форме?
Много раз после эры Windows 98 мы сталкивались с тем, что некоторые диалоги теряют Z-порядок и возвращаются к предыдущей форме.
Например:
Dialog1.ShowModal;
Dialog1.OnClickButton() : ShowMessage('anything');
Когда появляется MessageBox, он иногда не имеет фокуса и перемещается под Dialog1. Пользователи смущены этим, они говорят: мое приложение замерзло!!! Но если они используют Alt+Tab для перехода в другое приложение и обратно, фокус возвращается к MessageBox, и это будет окно переднего плана.
Мы испытали это с ShowMessage, MessageBox, обычными формами, а также с формами QuickReport.
Кто-нибудь знает об этом? Это ошибка Windows? Как вы можете предотвратить это? Как это поймать?
Спасибо за вашу помощь: dd
Я действительно сказал, что ПОСЛЕ Win98, поэтому эта проблема затрагивает все ОС (в том числе и Win7). Мы использовали Delphi 6 Prof, поэтому свойства не работают с формами по умолчанию.
Кто-то сказал, что диалоги сообщений управляются с помощью MessageBox + MB_APPLMODAL. Это хорошая новость, но у нас есть много старых форм и компонентов, сторонних инструментов.
Так что сложно сделать совершенно новое приложение с заменой форм.
Но мы постараемся сделать это.
Я думаю, что ответ - это половина проблемы приложения и половина проблемы Windows. Если Windows иногда справляется с этим, а иногда нет - похоже, это ошибка Windows. Но если мы можем заставить хорошее модальное создание окна, то это программная ошибка.
Может кто-нибудь объяснить мне, что означает флаг WS_POPUP? Есть ли у него побочный эффект или нет?
Спасибо: дд
4 ответа
Для старых версий 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);
Уловка, которую я использовал недавно, заключалась в применении этих двух строк кода при создании каждой формы:
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;
Часть, конечно, необязательна, но я использую ее, чтобы убедиться, что мои диалоги подтверждения и ошибки всегда видны пользователю.
Это похоже на небольшую работу, но в итоге мне больше не нужно беспокоиться о формах, случайно скрывающихся за другими формами.
Я полчаса просматривал эту страницу и часто задаваемые вопросы и до сих пор не могу найти, как оставить комментарий, так что прости меня за это нарушение протокола.
Прежде всего, я хотел бы прояснить, что плакат, имхо, не использует Windows 98. Он пишет "после эпохи Windows 98", что, как я понимаю, означает, что у него возникла эта проблема с версиями Windows после 98.
Поскольку у меня тоже есть эта проблема (CB2009), я хотел бы подчеркнуть вопрос автора "Это ошибка Windows?", На который я не нашел ответа. Если это ошибка Delphi/Builder, может быть, есть способ ее избежать? Я не вижу, как перехват всех возможных диалогов является работоспособным решением, и не избегаю использования fsStayOnTop. У меня есть форма настроек, которая должна оставаться поверх моей основной формы, но форма настроек может и будет иметь всплывающие диалоговые окна, которые при определенных условиях исчезнут в форме настроек.
Было бы очень полезно, если бы я понял, где поддержка z-порядка идет не так, как надо, поскольку это может дать подсказку о том, как этого избежать.