zoukankan      html  css  js  c++  java
  • 限制并方便用户输入

       防止用户误输入是软件开发的一项必不可少的工作,除才之外,还要为用户的使用提供最大方便。当然,我们可以利用或开发新的组件,以完成这些功能。但是,在团队开发中,每个成员都用自己认为不错的组件开发自己所承担的模块,会给软件的后期维护带来麻烦。交工的时候,项目负责人可不买你的帐。如果你用函数调用来完成这些功能,老盖也管不着。下面就是针对常用delphi组件的限制用户输入函数,但愿网友们能用的上。
    (一)TEdit、TDBEdit、TComboBox、TDBComboBox的输入
    分三种类型限制:
    (1)任意输入
    (2)整数输入
    (3)浮点数输入
    限制的项目如下:
    (1)整数输入只能输入数字0-9、+、-
    (2)浮点输入只能输入数字0-9、+、-、.
    (3)+和-只能有其一,并且只能出现在最前面
    (4).只能有一个
    (5)限制小数位数
    函数如下:
    procedure MxFormatKeyPress(Text:string;SelStart,SelLength:integer;
            var Key:Char;EditType:integer;Digits:integer);
    begin
      if (Key=#27) or (Key=#8) or (EditType=1) then exit;
      if EditType=2 then
        if not (Key in ['0'..'9','+','-'] ) then Key:=#0;
      if EditType=3 then
        if not (Key in ['0'..'9','+','-','.'] ) then Key:=#0;
      //控制+-
      if (Key ='-') or (Key='+' ) then begin
        if ((Pos('-',Text) > 0) or (Pos('+',Text) > 0 )) and
                (SelLength=0 ) then Key:=#0;
        if SelStart > 0 then Key:=#0;
      end;
      //控制.
      if (Key = '.') and (EditType=3 ) then begin
        if (Pos('.',Text) > 0) and (not((SelStart=Pos('.',Text) ))) then Key:=#0;
        if SelStart=0 then Key:=#0;
        if (Digits>0) and (SelStart+SelLength0) and (EditType=3) then
        if (pos('.',Text )>0 ) and (SelStart>=pos('.',Text)) then
          if length(Text)-pos('.',Text )>=Digits then Key:=#0;
    end;

    此函数在所限制组件的OnKeyPress事件中调用。Key即为OnKeyPress携带的Key:Char参数;EditType为限制的类型:1-任意输入;2-整数输入;3-浮点输入;Digits为浮点数输入时小数的位数,如果是零,则可输入任意位数。另外,此函数只适用于有Text、SelStart、SelLength等属性的TWinControl类的派生类。
    具体限制各组件的二级函数如下:

    限制TEdit、TDBEdit:
    procedure MxFormatEditKeyPress(Edit:TCustomEdit;var Key:Char;EditType:integer;
            Digits:integer);
    begin
      MxFormatKeyPress(Edit.Text,Edit.SelStart,Edit.SelLength,Key,EditType,Digits);
    end;

    限制TComboBox:
    procedure MxFormatComboKeyPress(Combo:TComboBox;var Key:Char;EditType:integer;
            Digits:integer);
    begin
      MxFormatKeyPress(Combo.Text,Combo.SelStart,Combo.SelLength,Key,EditType,Digits);
    end;

    限制TDBComboBox:
    procedure MxFormatDBComboKeyPress(Combo:TDBComboBox;var Key:Char;
            EditType:integer;Digits:integer);
    begin
      MxFormatKeyPress(Combo.Text,Combo.SelStart,Combo.SelLength,Key,EditType,Digits);
    end;

    调用示例:
    假如Form1上有一ComboBox1,让用户只输入浮点数,并且小数位数为两位。则可以在ComboBox1的OnKeyPress事件中调用上面的函数,代码如下:
    procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
    begin
      MxFormatComboKeyPress(Combobox1,Key,3,0);
    end;

    如果你的窗体上有多各TComboBox,并且限制类型一致,则不必每个TComboBox都书写代码,只需为其中一个编写事件处理代码,其它作连接即可。
    procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
    begin
      MxFormatComboKeyPress(Sender as TComboBox,Key,3,0);
    end;
    其它组件调用方法同上。

    (二)时间的输入
    限制类型:
    (1)时分
    (2)时分秒
    组件采用TMaskEdit,数据敏感采用TDBEdit。
    限制项目如下:
    (1)小时只能输入0-23
    (2)分钟不超过59
    (3)秒不超过59
    (4)用户只能全删,而不能只删某一位数据
    (5)箭头键可以更改时间
    需要在组件的OnKeyPress和OnKeyDown事件中分别书写代码。

    procedure MxFormatTimeKeyPress(ctl:TCustomMaskEdit;TimeFormat:integer;
            var Key:Char;dts:TDataSource);
    var
      TextSave:string;
      EditingPos:integer;//1-h 2-m 3-s
      i:integer;
      NumChars:set of Char;
      SelStartSave,SelLengthSave:integer;
      CharValid:boolean;
    begin
      NumChars:=['0'..'9'];
      if Key=^V then Key:=#0;
      if not (Key in NumChars ) then exit;
      TextSave:=ctl.Text;
      SelStartSave:=ctl.SelStart;
      SelLengthSave:=ctl.SelLength;
      case ctl.SelStart of
        0,1: EditingPos:=1;
        3,4: EditingPos:=2;
        6,7: EditingPos:=3;
        else EditingPos:=0;
      end;
      ///////////////////////////////////////
      CharValid:=true;
      case EditingPos of
        1: begin
          if SelStartSave=0 then begin
            if not (Key in ['0'..'2']) then CharValid := False;
            if (Key ='2' )  and (TextSave[2] in ['4'..'9']) then
              CharValid:=false;
          end;
          if (SelStartSave = 1) and (TextSave[1] = '2') and
                  (not (Key in ['0'..'3'])) then CharValid := False;
        end;
        2: if (SelStartSave = 3) and not (Key in ['0'..'5']) then CharValid := False;
        3: if (SelStartSave = 6) and not (Key in ['0'..'5']) then CharValid := False;
      end;
      if not CharValid then begin
        Key:=#0;exit;
      end;
      if dts<>nil then dts.DataSet.Edit;
      if not (SelStartSave in [2,5]) then TextSave[SelStartSave+1]:=Key;
      if SelLengthSave>1 then begin
        for i:=SelStartSave+2 to SelStartSave+SelLengthSave do
          if i in [1,2,4,5,7,8] then TextSave[i]:='0';
        SelLengthSave:=1;
      end;
      for i:=1 to length(TextSave) do
        if (i in [1,2,4,5,7,8]) and (not (TextSave[i] in NumChars ) ) then
          TextSave[i]:='0';
      ////////////////////////////////////
      if SelStartSave in [1,4] then
        SelStartSave :=SelStartSave+2
      else if SelStartSave=length(TextSave)-1 then
        SelStartSave :=SelStartSave
      else SelStartSave :=SelStartSave+1;
      /////////////////////////////////////
      ctl.Text :=TextSave;
      ctl.SelStart :=SelStartSave;
      ctl.SelLength :=SelLengthSave;
      Key:=#0;
    end;

    //此函数分割时间,因为有时候会遇到非法的时间字符串,所以不采用DecodeTime。
    function MxSplitStr(SourceStr,SplitStr:string;var ResultArray:array of string):integer;
    var
      i:integer;
      strTmp:string;
    begin
      strTmp:=SourceStr;
      i:=0;
      while pos(SplitStr,strTmp)>0 do begin
        ResultArray[i]:=copy(strTmp,1,pos(SplitStr,strTmp)-1);
        strTmp:=copy(strTmp,pos(SplitStr,strTmp)+length(SplitStr),length(strTmp)-
            pos(SplitStr,strTmp));
        i:=i+1;
      end;
      ResultArray[i]:=strTmp;
      result:=i+1;
    end;
    //此函数检查字符串是否为合法的时间
    function TimeValid(TimeStr:string;TimeFormat:integer):boolean;
    var
    h,m,s:string;
    ary:array[0..2] of string;
    SplitRet:integer;
    i:integer;
    begin
      result:=true;
      SplitRet:=MxSplitStr(TimeStr,':',ary);
      if SplitRet<2 then begin
        result:=false; exit;
      end;
      for i:=0 to 2 do begin
        if length(ary[i])>2 then begin
          result:=false; exit;
        end;
        ary[i]:=trim(ary[i]);
      end;
      h:=ary[0];m:=ary[1];
      if TimeFormat=3 then s:=ary[2];
      ///////////////////////////////
      if (h=') or (strtoint(h)>23 ) then begin
        result:=false; exit;
      end;
      if (m=' ) or (strtoint(m)>59) then begin
        result:=false; exit;
      end;
      if (TimeFormat=3) then
        if (s=') or (strtoint(s)>59) then begin
          result:=false; exit;
        end;
    end;
    //此函数对时分秒进行加减运算
    function IncTime(ATime: TDateTime; Hours, Minutes, Seconds,
      MSecs: Integer): TDateTime;
    begin
      Result := ATime + (Hours div 24) + (((Hours mod 24) * 3600000 +
        Minutes * 60000 + Seconds * 1000 + MSecs) / MSecsPerDay);
      if Result < 0 then Result := Result + 1;
    end;
    //时分秒加减运算的二级函数
    function TimeAdd(TimeStr:string;TimeFormat:integer;
            HStep,MStep,SStep:integer):string;
    var
      dt:Tdatetime;
    begin
      if not TimeValid(TimeStr,TimeFormat) then
        if TimeFormat=2 then begin result:='00:00'; exit; end
        else begin result:='00:00:00';exit; end;
      dt:=strtotime(TimeStr);
      if TimeFormat=2 then
        result:=FormatDateTime('hh:mm',IncTime(dt,HStep,MStep,SStep,0))
      else
        result:=FormatDateTime('hh:mm:ss',IncTime(dt,HStep,MStep,SStep,0))
    end;
    //限制组件的OnKeyDown
    procedure MxFormatTimeKeyDown(ctl:TCustomMaskEdit;TimeFormat:integer;
            var Key:word;Shift: TShiftState;dts:TDataSource);
    var
      TextSave:string;
      SelStartSave,SelLengthSave:integer;
      EditingPos:integer;//1-h 2-m 3-s
      i:integer;
    begin
      if (ssShift in Shift) and (Key<>vk_delete ) then exit;
      if not (Key in [vk_delete,vk_back,vk_up,vk_down] ) then exit;
      if (dts<>nil ) and (not dts.DataSet.Active  ) then exit;
      if (dts<>nil) and (not dts.DataSet.Modified ) then
        dts.DataSet.Edit;
      //////////////////////////////////////
      TextSave:=ctl.Text;
      SelStartSave:=ctl.SelStart;
      SelLengthSave:=ctl.SelLength;
      case SelStartSave of
        0,1: EditingPos:=1;
        3,4: EditingPos:=2;
        6,7: EditingPos:=3;
        else EditingPos:=0;
      end;
      if SelStartSave=length(TextSave) then
        EditingPos:=TimeFormat;
      if Key=vk_delete then begin
        if SelLengthSave=length(TextSave) then TextSave:='
        else begin
          if not (SelStartSave in [2,5]) then TextSave[SelStartSave+1]:='0';
          if SelLengthSave>1 then begin
            for i:=SelStartSave+2 to SelStartSave+SelLengthSave do
              if i in [1,2,4,5,7,8] then TextSave[i]:='0';
            SelLengthSave:=1;
          end;
        end;
        Key:=0;
      end;
      if Key=vk_back then begin
        if SelLengthSave=length(TextSave) then TextSave:='
        else if SelLengthSave<=1 then begin
          if not (SelStartSave in [3,6]) then begin
            TextSave[SelStartSave]:='0';
            SelStartSave:=SelStartSave-1;
          end else begin
            TextSave[SelStartSave-1]:='0';
            SelStartSave:=SelStartSave-2;
          end;
          SelLengthSave:=1;
        end else begin
          for i:=SelStartSave+1 to SelStartSave+SelLengthSave do
            if i in [1,2,4,5,7,8] then TextSave[i]:='0';
          SelLengthSave:=1;
        end;
        Key:=0;
      end;
      ///////////////////////////////////////
      if (Key=vk_up) or (Key=vk_down ) then begin
        if trim(TextSave)=':' then begin
          if TimeFormat=2 then TextSave:='00:00'
          else TextSave:='00:00:00'
        end else begin
          if Key=vk_up then
            case EditingPos of
              1: TextSave:=TimeAdd(TextSave,TimeFormat,1,0,0);
              2: TextSave:=TimeAdd(TextSave,TimeFormat,0,1,0);
              3: TextSave:=TimeAdd(TextSave,TimeFormat,0,0,1);
            end;
          if Key=vk_down then
            case EditingPos of
              1: TextSave:=TimeAdd(TextSave,TimeFormat,-1,0,0);
              2: TextSave:=TimeAdd(TextSave,TimeFormat,0,-1,0);
              3: TextSave:=TimeAdd(TextSave,TimeFormat,0,0,-1);
            end;
        end;
      end;
      ///////////////////////////////////////
      ctl.Text :=TextSave;
      ctl.SelStart :=SelStartSave;
      ctl.SelLength :=SelLengthSave;
    end;
    以上函数的TimeFormat参数代表时间的类型:1-时:分;2-时:分:秒
    要完成对时间的输入限制,只需调用上面的MxFormatTimeKeyPress,MxFormatTimeKeyDown两个函数。
    调用示例:
    (1)TMaskEdit
    procedure TForm1.MaskEdit1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      MxFormatTimeKeyDown(Sender as TCustomMaskEdit,2,Key,Shift,nil);
    end;

    procedure TForm1.MaskEdit1KeyPress(Sender: TObject; var Key: Char);
    begin
      MxFormatTimeKeyPress(Sender as TCustomMaskEdit,2,Key,nil);
    end;
    并且,TMaskEdit的EditMask属性设为'99:99'
    (2)TDBEdit

    procedure TForm1.DBEdit1KeyPress(Sender: TObject; var Key: Char);
    begin
      MxFormatTimeKeyPress(Sender as TCustomMaskEdit,2,Key,(Sender as TDBEdit).DataSource);
    end;

    procedure TForm1.DBEdit1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      MxFormatTimeKeyDown(Sender as TCustomMaskEdit,2,Key,Shift,(Sender as TDBEdit).DataSource);
    end;
    在TDBEdit所连接的数据源打开后,设定所连字段的EditMask属性为99:99:
      DBEdit1.Field.EditMask :='99:99';

    (三)日期的输入
    采用Rx的日期组件TDateEdit、TDBDateEdit。如果你还没安装,请在本站下载。
    无需对日期的输入作限制,只需方便用户的输入。即:箭头键可以改变相应的日期元素,因为Rx五次功能。函数如下:
    procedure MxSpinRxDateEdit(Edit:TCustomDateEdit;Key:word;Shift:TShiftState;
            dts:TDataSource);
    var
      DateStr,Mark,str:string;
      MarkPos1,MarkPos2:integer;
      DateOrd:TDateOrder;
      DateFlag,step:integer;
      OldSelStart:integer;
    begin
      if Shift<>[] then exit;
      if not (Key in [vk_up,vk_down] ) then exit;
      if (dts<>nil ) and (not dts.DataSet.Active  ) then exit;
      if (dts<>nil ) and (not dts.DataSet.Modified) then
        dts.DataSet.Edit;
      OldSelStart:=Edit.SelStart;
      DateStr:=Edit.EditText;
      Mark:=GetDateMark(DateStr);
      MarkPos1:=pos(Mark,DateStr);
      str:=copy(DateStr,MarkPos1+1,length(DateStr)-MarkPos1);
      MarkPos2:=MarkPos1+pos(Mark,str);
      DateOrd:=GetDateOrder(ShortDateFormat);
      DateFlag:=GetDateFlag(MarkPos1,MarkPos2,Edit.SelStart,DateOrd);
      if Key=vk_up then step:=1
      else if Key=vk_down then step:=-1
      else step:=0;
      case DateFlag of
        1: Edit.Date := IncYear(Edit.Date ,step);
        2: Edit.Date := IncMonth(Edit.Date ,step);
        3: Edit.Date := IncDay(Edit.Date ,step);
      end;
      Edit.SelStart :=OldSelStart;
    end;

    此函数在组件的OnKeyDown事件中调用,对于TDateEdit,DataSoure参数为nil。
    记着引用Rx的单元ToolEdit和DateUtil。
    调用示例:
    procedure TForm1.DateEdit1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      MxSpinRxDateEdit(Sender as TCustomDateEdit,Key,Shift,nil);
    end;

    procedure TForm1.DBDateEdit1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      MxSpinRxDateEdit(Sender as TCustomDateEdit,Key,Shift,(Sender as TDBDateEdit).DataSource);
    end;
  • 相关阅读:
    扩展卢卡斯定理
    扩展中国剩余定理
    扩展欧拉定理
    拓展BSGS
    删边最短路
    树 上 差分
    P4568 JLOI 飞行路线 分层最短路板子
    最短路相关
    P3758 TJOI2017 可乐
    bzoj4173 数学
  • 原文地址:https://www.cnblogs.com/y232995558/p/1451208.html
Copyright © 2011-2022 走看看