Подтвердить что ты не робот

Выход из формы с помощью ModalResult

У меня есть куча форм, и я хочу автоматизировать их, чтобы они открывались и закрывались сами по себе.

Я знаю, как заставить их открываться (имея функцию OnActivate), но у меня проблемы с их закрытием.

Так, например, у меня есть

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  inherited;
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      ModalResult := mrOK;
    end;    
end;

который выполняет функцию. Я хочу закрыть окно после запуска функции, что и должен сделать ModalResult.

(Я также попытался добавить строку ModalResult в самом конце процедуры RunBtnClick, но это тоже не сработало)

и я создаю форму следующим образом:

ProgForm := TProgressForm.Create(Self, FModItem);
Self.Visible := False;
try
 if ProgForm.ShowModal = mrOK then
  begin
    Left := ProgForm.Left;
    Top := ProgForm.Top;
  end;

Мне удалось создать кнопки, чтобы закрыть форму, просто добавив mrOK в Modal Result в Object Inspector, но я не могу явно это сделать

Может ли кто-нибудь понять, почему он не работает?

Спасибо

4b9b3361

Ответ 1

Причиной неработоспособности является то, что VCL активно устанавливает ModalResult в 0 в TCustomForm.ShowModal после отображения формы, но до начала проверки изменений в ModalResult. Поэтому в OnActivate и OnShow вы должны быть ранними.

Решение заключается в задержке уведомления. Это можно сделать с помощью PostMessage следующим образом:

const
  UM_ACTIVATED = WM_USER + 1;

type
  TProgressForm = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    procedure UMActivated(var Message: TMessage); message UM_ACTIVATED;
  end;

...

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  PostMessage(Handle, UM_ACTIVATED, 0, 0);
end;

procedure TProgressForm.UMActivated(var Message: TMessage);
begin
  { Your code here }
  ModalResult := mrOk;
end;

Источник: NLDelphi

Ответ 2

Я переопределяю ShowModal и выполняю те тесты, которые вы сейчас выполняете в OnActvate. Это имеет два больших преимущества:

  • Не отображает форму вообще, если ее не нужно показывать. Инициирование завершения формы из OnActivate заставляет форму "мерцать" на экране: она отображается и сразу же снимается.
  • Не полагается на код, который не под вашим контролем. Вы больше не заботитесь о порядке работы в предке ShowModal, потому что вы вызываете его только в том случае, если форма должна действительно отображаться.

Конечно, использование элемента GUI (формы) таким образом - это немного запаха кода, потому что он в основном использует графический интерфейс без необходимости взаимодействия с пользователем. Это, без сомнения, может быть реорганизовано для использования промежуточной функции, которая возвращает mrOk и делает то, что RunBtnClick() делает без необходимости использования GUI, и создает Form только при необходимости. Я предполагаю, что это выгодная ситуация.

код:

TMyForm = class(TForm)
....
public
  function ShowModal:Integer;override;
end;

function TMyForm.ShowModal:Integer;
begin
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      Result := mrOK;
    end
  else
    Result := inherited ShowModal;
end;

Ответ 3

Событие OnActivate запускается до того, как ModalResult будет reset в mrNone в TCustomForm.ShowModal. Это означает, что изменение ModalResult в обработчике OnActivate игнорируется.

  function TCustomForm.ShowModal: Integer;
  Show;
  try
    SendMessage(Handle, CM_ACTIVATE, 0, 0);  << Your onActivate is called here
    ModalResult := 0; << ModalResult is reset

Ответ 4

Посмотрите на TCustomForm.ShowModal(внутри forms.pas): ModalResult проверяется не ранее, пока сообщение CM_ACTIVATE не будет отправлено (указанное сообщение вызывает ваш вызов OnActivate); на самом деле, он установлен в 0 сразу же после вызова OnActivate, поэтому неудивительно, что ваше задание не работает.

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

if ModalResult=0 then 
     SendMessage(Handle, CM_ACTIVATE, 0, 0);

в верхней части обработчика событий.