内容简介:!错误!在 Android 下这么用 ShowModal 是错误的!
1、直接调用 ShowModal 肯定是不行的,Android 下直接抛出异常。而 iOS、OSX、Windows 下是没问题的。
2、像下面这样用循环模拟 ShowModal 也是不行的,如果只是这么简单,Delphi 早就实现了。这个代码在我手机上实测存在的主要问题就是你按回退键没响应。
Delphi/Pascal
var F:TForm2; begin F:=TForm2.Create(nil); F.Show; while F.Visible and (F.ModalResult=mrNone) do begin Application.ProcessMessages; Sleep(10); end; FreeAndNil(F); end;
var F:TForm2; begin F:=TForm2.Create(nil); F.Show; while F.Visibleand (F.ModalResult=mrNone) do begin Application.ProcessMessages; Sleep(10); end; FreeAndNil(F); end;
3、像下面的用法也是错误的:
Delphi/Pascal
procedure TForm1.Button1Click(Sender:TObject) var dlg: TForm2; begin dlg := TForm2.Create(nil); dlg.ShowModal( procedure(ModalResult: TModalResult) begin if ModalResult = mrOK then if dlg.ListBox1.ItemIndex >= 0 then edit1.Text := dlg.ListBox1.Items [dlg.ListBox1.ItemIndex]; dlg.DisposeOf; end); end;
procedure TForm1.Button1Click(Sender:TObject) var dlg: TForm2; begin dlg := TForm2.Create(nil); dlg.ShowModal( procedure(ModalResult: TModalResult) begin if ModalResult = mrOKthen if dlg.ListBox1.ItemIndex >= 0 then edit1.Text := dlg.ListBox1.Items [dlg.ListBox1.ItemIndex]; dlg.DisposeOf; end); end;
这个的问题在于 dlg 是局部变量,ShowModal 回调的匿名函数里访问Button1Click 里的局部变量是不安全的(栈可能已经错乱)。这块 FMX 的设计真是一个败笔,应该加入实例的地址。当然了,如果 dlg 是一个全局变量,上面的代码就不存啥问题了。
正确的用法:
好吧,得罪了人,批判了别人的不对,总得给出一个对的方法吧。这个方法实际上也说不上真正的对,我暂时称之为对是因为这是目前我能想到的相对完美的解决方案。
Delphi/Pascal
type TFormModalProc = reference to procedure(F: TForm); TFormModalHook = class(TComponent) private FForm: TForm; FCloseAction: TCloseAction; FOldClose: TCloseEvent; FResultProc: TFormModalProc; procedure DoFormClose(Sender: TObject; var Action: TCloseAction); public constructor Create(AOwner: TComponent); override; procedure ShowModal(AResult: TFormModalProc); end; procedure ModalDialog(F: TForm; OnResult: TFormModalProc; ACloseAction: TCloseAction = TCloseAction.caFree); var AHook: TFormModalHook; begin AHook := TFormModalHook.Create(F); AHook.FCloseAction := ACloseAction; AHook.ShowModal(OnResult); end; { TFormModalHook } constructor TFormModalHook.Create(AOwner: TComponent); begin inherited Create(AOwner); FForm := AOwner as TForm; FOldClose := FForm.OnClose; FForm.OnClose := DoFormClose; FCloseAction := TCloseAction.caFree; end; procedure TFormModalHook.DoFormClose(Sender: TObject; var Action: TCloseAction); begin if FForm.ModalResult = mrNone then FForm.ModalResult := mrCancel; Action := FCloseAction; if Assigned(FOldClose) then FOldClose(Sender, Action); end; procedure TFormModalHook.ShowModal(AResult: TFormModalProc); begin FResultProc := AResult; {$IFDEF ANDROID} FForm.ShowModal( procedure(AResult: TModalResult) var AHook: TFormModalHook; AForm: TForm; I: Integer; AChild: TComponent; begin if Screen.ActiveForm is TForm then AForm := Screen.ActiveForm as TForm else begin raise Exception.Create('You should not in here.'); end; if Assigned(AForm) then begin AForm.OnClose := FOldClose; for I := 0 to AForm.ComponentCount - 1 do begin AChild := FForm.Components[I]; if AChild is TFormModalHook then begin (AChild as TFormModalHook).FResultProc(AForm); FreeAndNil(AChild); Break; end; end; end; end); {$ELSE} FForm.ShowModal; FResultProc(FForm); {$ENDIF} end;
type TFormModalProc = referenceto procedure(F: TForm); TFormModalHook = class(TComponent) private FForm: TForm; FCloseAction: TCloseAction; FOldClose: TCloseEvent; FResultProc: TFormModalProc; procedure DoFormClose(Sender: TObject; var Action: TCloseAction); public constructor Create(AOwner: TComponent); override; procedure ShowModal(AResult: TFormModalProc); end; procedure ModalDialog(F: TForm; OnResult: TFormModalProc; ACloseAction: TCloseAction = TCloseAction.caFree); var AHook: TFormModalHook; begin AHook := TFormModalHook.Create(F); AHook.FCloseAction := ACloseAction; AHook.ShowModal(OnResult); end; { TFormModalHook } constructor TFormModalHook.Create(AOwner: TComponent); begin inherited Create(AOwner); FForm := AOwneras TForm; FOldClose := FForm.OnClose; FForm.OnClose := DoFormClose; FCloseAction := TCloseAction.caFree; end; procedure TFormModalHook.DoFormClose(Sender: TObject; var Action: TCloseAction); begin if FForm.ModalResult = mrNonethen FForm.ModalResult := mrCancel; Action := FCloseAction; if Assigned(FOldClose) then FOldClose(Sender, Action); end; procedure TFormModalHook.ShowModal(AResult: TFormModalProc); begin FResultProc := AResult; {$IFDEFANDROID} FForm.ShowModal( procedure(AResult: TModalResult) var AHook: TFormModalHook; AForm: TForm; I: Integer; AChild: TComponent; begin if Screen.ActiveFormis TFormthen AForm := Screen.ActiveFormas TForm else begin raise Exception.Create('You should not in here.'); end; if Assigned(AForm) then begin AForm.OnClose := FOldClose; for I := 0 to AForm.ComponentCount - 1 do begin AChild := FForm.Components[I]; if AChildis TFormModalHookthen begin (AChildas TFormModalHook).FResultProc(AForm); FreeAndNil(AChild); Break; end; end; end; end); {$ELSE} FForm.ShowModal; FResultProc(FForm); {$ENDIF} end;
好吧,代码看起来有点多,多就多吧。用法很简单,用它替换 TForm.ShowModal 方法,如:
Delphi/Pascal
procedure TForm1.Button1Click(Sender: TObject); var F: TForm2; begin F := TForm2.Create(nil); ModalDialog(F, procedure(AForm: TForm) begin ShowMessage(AForm.Name + ' Modal result ready'); end); end;
procedure TForm1.Button1Click(Sender: TObject); var F: TForm2; begin F := TForm2.Create(nil); ModalDialog(F, procedure(AForm: TForm) begin ShowMessage(AForm.Name + ' Modal result ready'); end); end;
【注意】
不要在 ModalDialog 的回调函数中,在可能引发消息循环处理的地方,如:ShowMessage/MessageDlg/ProcessMessages 等函数的后面再引用 AForm 的地址,因为在 FMX 框架下,它很可能会被释放掉了。
以上所述就是小编给大家介绍的《!错误!在 Android 下这么用 ShowModal 是错误的!》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Golang学习笔记之错误处理error、panic (抛出错误),recover(捕获错误)
- c – 构建PBRT v2错误 – 错误1错误U1077:’if’:返回代码’0x1′
- Google开源ClusterFuzz:使得查找错误并修复错误变得异常简单
- 脚本错误量极致优化-定位压缩且无 SourceMap 文件的脚本错误
- php – 解析错误:语法错误,意外’未设置'(T_UNSET)
- 可以让程序告诉我详细的页面错误和数据库连接错误吗?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Python
Paul Barry / O'Reilly Media / 2010-11-30 / USD 49.99
Are you keen to add Python to your programming skills? Learn quickly and have some fun at the same time with Head First Python. This book takes you beyond typical how-to manuals with engaging images, ......一起来看看 《Head First Python》 这本书的介绍吧!