Выход из формы с помощью 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, но я не могу явно это сделать
Может ли кто-нибудь понять, почему он не работает?
Спасибо
Ответы
Ответ 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);
в верхней части обработчика событий.