[FMX] Android 下如何让编辑框中只输入数字

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;

 

分享到: