Пару месяцев назад Марко Канту порадовал нас информацией о том, что Android не поддерживает модальные формы и поэтому теперь у нас в Delphi XE5 будет два разных метода ShowModal:
function ShowModal: TModalResult; overload; procedure ShowModal(const ResultProc: TProc<TModalResult>); overload;
Обращение к первому методу на Android вызывает исключение, а второй предлагается использовать следующим образом.
Вместо такого кода:
var dlg: TForm1; begin dlg := TForm1.Create(nil); try // select current value, if avaialble in the list dlg.ListBox1.ItemIndex := dlg.ListBox1.Items.IndexOf(edit1.Text); if dlg.ShowModal = mrOK then // if OK was pressed and an item is selected, pick it if dlg.ListBox1.ItemIndex >= 0 then edit1.Text := dlg.ListBox1.Items [dlg.ListBox1.ItemIndex]; finally dlg.Free; end; end;
нужно писать такой:
var dlg: TForm1; begin dlg := TForm1.Create(nil); // select current value, if avaialble in the list dlg.ListBox1.ItemIndex := dlg.ListBox1.Items.IndexOf(Edit1.Text); dlg.ShowModal( procedure(ModalResult: TModalResult) begin if ModalResult = mrOK then // if OK was pressed and an item is selected, pick it if dlg.ListBox1.ItemIndex >= 0 then edit1.Text := dlg.ListBox1.Items [dlg.ListBox1.ItemIndex]; dlg.DisposeOf; end); end;
Идея ясна и мотивация вполне понятна. Код, который должен выполниться после закрытия формы, перемещается в анонимную процедуру, которая и будет вызвана в нужный момент.
Этот код будет работать на всех платформах. Спасибо, Марко!
Но есть нюанс. Давайте заглянем внутрь новой версии ShowModal:
procedure TCommonCustomForm.ShowModal(const ResultProc: TProc<TModalResult>); begin FResultProc := ResultProc; Show; end;
Такая форма будет одинаково немодальна на всех платформах! То есть, если мы хотим писать кроссплатформенных код, нам предлагают либо усыпать код IFDEF-ами, либо отказаться от использования модальных форм совсем. Как-то это нехорошо.
Не знаю как у вас, но у меня в коде часто встречается что-то такое:
with TForm1.Create(nil) do try ShowModal; finally Free; end;
С учетом андроида этот код можно переписать следующим образом:
var Frm: TForm1; begin Frm := TForm1.Create(nil); ShowModal(procedure (Res: TModalResult) begin Frm.DisposeOf; end); end;
Этот вариант корректно работает на всех платформах, но форма перестает быть модальной и это приемлемо далеко не всегда. Поэтому оптимальный для меня вариант будет выглядеть так:
var Frm: TForm1; begin Frm := TForm1.Create(nil); {$IFDEF ANDROID} Frm.ShowModal(procedure (Res: TModalResult) begin end); {$ELSE} try Frm.ShowModal; finally Frm.Free; end; {$ENDIF} end;
Этот код обеспечит модальность формы в обычных случаях и «всевдомодальность» на андроиде. Но как-то это не очень красиво. Не люблю применять IFDEF-ы по пустякам. Таких мест в коде может быть много.
Подведу итог. В связи с вышеизложенным у меня есть два риторических вопроса.
1) Почему нельзя было новый ShowModal реализовать хотя бы так:
procedure TCommonCustomForm.ShowModal(const ResultProc: TProc<TModalResult>); begin {$IFDEF ANDROID} FResultProc := ResultProc; Show; {$ELSE} ResultProc(ShowModal); {$ENDIF} end;
?
2) Если такой подход все-таки чем-то не устраивает, то зачем было называть новый метод ShowModal, ведь он с модальными формами никак не связан?
1. Николай Зверев
8 Дек 2013 6:35 пп
Да, вопросы, вопросы и вопросы…
Вот, кстати, в данном примере очень подойдут хелперы
2. Роман Янковский
8 Дек 2013 7:28 пп
Оказывается, эту проблему первым поднял не я (вполне ожидаемо). Вот хороший пост по теме: http://delphihaven.wordpress.com/2013/10/26/new-showmodal-overload/
Кроме того, о чем я здесь написал, оказалось, что в таких «псевдомодальных» формах присваивание значения ModalResult не приводит к закрытию формы. Это все обязательно нужно фиксить.
3. Ахан
14 Июл 2014 3:55 пп
procedure TCommonCustomForm.ShowModal(const ResultProc: TProc);
begin
FResultProc := ResultProc;
Show;
end;
Что за поле FResultProc? Где описан№