Модальные формы, скрытые формами fsStayOnTop
У меня есть форма (TBigForm в примере ниже), которая позволяет манипулировать некоторыми сложными данными и нуждается в дополнительной информации для отображения. Я поместил эту информацию в форму fsStayOnTop (в примере OnTopForm), чтобы она всегда была видимой, но при необходимости ее можно было убрать с дороги. Теперь, когда какое-то действие пользователя в TBigForm показывает модальную форму, это часто скрывается за OnTopForm, что заставляет приложение выглядеть замороженным. Как я могу избежать этого? (Поиск дает много-много хитов, но я не смог найти решение из них.)
В моем реальном приложении есть много мест, где отображаются модальные формы, поэтому я хотел бы избежать изменения всех этих вызовов.
Пример: создайте новое приложение VCL, перетащите TButton на форму Form1, дважды щелкните кнопку и замените созданную заглушку реализации Button1Click следующим:
type
TBigForm = class(TForm)
strict private
OnTopForm: TForm;
Button1: TButton;
procedure Button1Click(Sender: TObject);
protected
procedure DoHide; override;
procedure DoShow; override;
public
constructor Create(AOwner: TComponent); override;
end;
{ TBigForm }
procedure TBigForm.Button1Click(Sender: TObject);
begin
ShowMessage('Test');
end;
constructor TBigForm.Create(AOwner: TComponent);
begin
inherited CreateNew(AOwner);
Caption := 'Big form';
WindowState := wsMaximized;
Button1 := TButton.Create(Self);
Button1.Parent := Self;
Button1.Caption := 'Freeze!';
Button1.SetBounds(10, 10, 100, 100);
Button1.OnClick := Button1Click;
end;
procedure TBigForm.DoHide;
begin
OnTopForm.Free;
inherited DoHide;
end;
procedure TBigForm.DoShow;
begin
inherited DoShow;
OnTopForm := TForm.Create(Self);
OnTopForm.Caption := 'Important information';
OnTopForm.BorderStyle := bsToolWindow;
OnTopForm.FormStyle := fsStayOnTop;
OnTopForm.Position := poScreenCenter;
OnTopForm.Show;
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
f: TBigForm;
begin
f := TBigForm.Create(nil);
try
f.ShowModal;
finally
f.Free;
end;
end;
Запустите приложение, нажмите "Button1", а затем "Freeze!".
(Кстати: мы используем D2007.)
4 ответа
Временно измените FormStyle вашей OnTopform перед отображением другой формы как модальной:
procedure TBigForm.Button1Click(Sender: TObject);
begin
OnTopForm.FormStyle := fsNormal;
ShowMessage('Test');
OnTopForm.FormStyle := fsStayOnTop;
end;
Это должно работать на то, что вы хотите...
Попробуйте задать для свойства модальной формы PopupParent значение формы StayOnTop или установите для свойства Application.ModalPopupMode значение, отличное от pmNone, перед вызовом ShowModal().
procedure TForm1.ScreenOnActiveFormChange(Sender: TObject);
begin
if (Screen.ActiveForm <> nil) then
begin
if (Screen.ActiveForm.Handle <> Application.MainForm.Handle) then
with Screen.ActiveForm do
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
Windows.SetForeGroundWindow(Screen.ActiveForm.Handle);
end;
end;
Это должно работать.
Вот ваш вкус
Create an global TApplicationEvents
Declare an global var to keep track of modal form count
Hookup the OnMessage
var
Ctrl: TControl;
if Msg.hwnd <> 0 then
case Msg.message of
CM_ACTIVATE,
CM_DEACTIVATE:
begin
Ctrl := FindControl(Msg.hwnd);
if Ctrl is TForm then
if fsModal in TForm(Ctrl).FormState then
begin
if Msg.message = CM_ACTIVATE then
Inc(Modal form count var)
else
Dec(Modal form count var);
add more logic based on Modal form count var
end;
end;
end;
Повеселись