Пару месяцев назад Марко Канту порадовал нас информацией о том, что 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? Где описан№