XE 7 中 Android 下,字符不会触发 OnKeyDown 事件,所以你无法再在编辑框中过滤一些特殊字符,禁止用户输入。虽然 XE7 的TEdit 提供了一个 FilterChar ,但遗憾的是它依然不好。通过分析,其提供了一个 OnValidating 方法在用户输入一个字符时,触发来让您验证输入的有效性。但不幸的是,你在 OnValidating 中修改 Text 的值不会影响显示的效果,个人认为这是一个Bug,问题发生在 FMX.Edit.Style.pas 中:
procedure TStyledEdit.EndIMEInput; begin Model.DisableNotify; try Model.Text := FTextService.CombinedText; finally Model.EnableNotify; end; FTextService.Text := FTextService.CombinedText;//此行应为 FTextService.Text:=Model.Text; FTextService.CaretPosition := Point(GetOriginCaretPosition + FTextService.CombinedText.Length - FTextService.Text.Length, 0); RepaintEdit; end;
但修改源码我并不觉得是一个好办法,暂时,我们可以通过异步触发一个事件来修改编辑框的内容:
procedure TForm1.Edit1Validating(Sender: TObject; var Text: string); var p,pd,pds:PQCharW; d,e:Integer; S:String; begin if Length(Text)>0 then begin SetLength(S,Length(Text)); p:=PQCharW(Text); pd:=PQCharW(S); pds:=pd; if p^ in ['+','-'] then begin Inc(p); pd^:=p^; Inc(pd); end; d:=0; e:=0; while p^<>#0 do begin if p^ in ['0'..'9'] then begin pd^:=p^; Inc(pd); end else if p^='.' then begin Inc(d); if d=1 then begin pd^:=p^; Inc(pd); end; end else if p^ in ['e','E'] then begin Inc(e); if e=1 then begin if d<=1 then begin pd^:=p^; Inc(pd); end; end; end; Inc(p); end; Workers.Post(procedure (AJob:PQJob) begin Form1.Edit1.Text:=AJob.ExtData.AsString; end,TQJobExtData.Create(StrDupX(pds,pd-pds)),True,jdfFreeAsObject); end; end;
上面的代码让其只能输入数字,对于非数字的键值将被直接过滤掉。注意,我用到了 QWorker.Post 方法和 QString.StrDupX 函数,您可以替换它们为自己类似的方法,如:在FMX中实现PostMessage的方法。
QString 中提供了一个 FilterCharW 函数和 FilterNoNumberW 函数来提供一些辅助的过滤功能,上面的代码如果用 FilterNoNumberW 可以直接简化为:
procedure TForm1.Edit1Validating(Sender: TObject; var Text: string); begin if Length(Text)>0 then begin Workers.Post(procedure (AJob:PQJob) begin Form1.Edit1.Text:=AJob.ExtData.AsString; end,TQJobExtData.Create(FilterNoNumberW(Text)),True,jdfFreeAsObject); end; end;