【问题标题】:How to prevent user from leaving a DBGrid's cell depending on it's value如何防止用户根据其值离开 DBGrid 的单元格
【发布时间】:2014-06-06 20:51:55
【问题描述】:

这是我的情况: 我有一个任务,我需要使用 TClientDataSet 进行一些操作(是的,我必须使用这个特定的组件)。用户将能够编辑 TClientDataSet 中的数据,因此我使用连接到 TDataSource 的 TDBGrid,该 TDataSource 连接到我的 TClientDataSet。

我需要做的是根据它的值防止用户离开单元格(将焦点移动到程序中的其他地方)。有效值是从 00:00 到 23:59 的时间。它不能为空或包含空白字符。我正在使用 TClientDataSet 字段的 EditMask 属性,因此很容易以正确的格式直接键入。

示例: 如果用户在单元格中键入 29:00,然后尝试移动到另一个单元格(或另一个组件),我希望能够停止该操作,并让他在单元格中输入一些其他有效值(如 15:00 ),然后他可以离开它并做其他事情(比如编辑另一个单元格)。

进行此类验证的选项有哪些?我正在使用 Borland Delphi 7。

谢谢。

【问题讨论】:

    标签: delphi validation delphi-7 tclientdataset dbgrid


    【解决方案1】:

    使用TField.OnValidate 事件。这是在EditMask 被验证之后,但在数据实际写入记录缓冲区之前调用的。这允许您在完成基本字符验证后进行更广泛的验证。

    事件将Sender参数中正在验证的字段接收到TFieldNotifyEvent

    TFieldNotifyEvent = procedure(Sender: TField) of Object;
    

    您可以执行您需要执行的操作来验证该事件中的数据,并在新值不满足您的时间跨度要求时引发异常。例如,如果在字段中输入少于 2 个字符,以下内容将引发异常:

    procedure TForm4.ClientDataSet1ClientDataSet1Field1Validate(Sender: TField);
    begin
      if not (Length(Trim(Sender.AsString)) > 1) then
        raise Exception.Create('Invalid length for field content.');
    end;
    

    另一种方法是改用TDBGrid.OnColExit 事件,但我更喜欢将数据验证代码与数据库内容更直接地保存在一起,而不是将其绑定到用户界面的特定部分。 (将其保存在数据库中,即使您稍后改变主意并从使用网格切换到使用单独的表单进行记录维护,或者当您从代码而不是 UI 设置字段值时,它也会自动执行。)

    就实际验证数据本身而言,最简单的方法是使用TRegEx,如果它在您使用的Delphi 版本中可用。像这样的表达式应该可以工作:

    var
      FoundMatch: Boolean;
      TimeStr: string;
    begin
      TimeStr := Sender.AsString;
      FoundMatch := TRegEx.IsMatch(TimeStr,
            '\A([0-1][0-9]|[2][0-3]):[0-5][0-9]\z', [roMultiLine]);
      if not FoundMatch then
        raise Exception.CreateFmt('Invalid time value %s', [TimeStr]);
    end;
    

    如果您的 Delphi 版本中没有 TRegEx,您可以在 Regular-Expressions.info 网站上找到免费的开源 TPerlRegEx;它是当前 Delphi 版本中用于其正则表达式支持核心的代码。在这种情况下,这段代码也应该可以工作:

    var
        Regex: TPerlRegEx;
        FoundMatch: Boolean;
        TimeStr: string;
    begin
      TimeStr := Sender.AsString;
      Regex := TPerlRegEx.Create;
      try
        Regex.RegEx := '\A([0-1][0-9]|[2][0-3]):[0-5][0-9]\z';
        Regex.State := [preNotEmpty];
        Regex.Subject := TimeStr;
        FoundMatch := Regex.Match;
        if not FoundMatch then
          raise Exception.CreateFmt('Invalid time value %s', [TimeStr]);
      finally
        Regex.Free;
      end;
    end;
    

    【讨论】:

    • 我使用 OnValidate 方法创建的代码编辑了我的问题。它不会引发一个简单的“测试”异常。
    • 也许我没有正确处理异常。我是否必须添加任何其他代码来实际进行我想要的预防,或者只是引发该异常来阻止用户进行的任何其他操作?
    • 如果你在场上有一个 EditMask,那么 Length 永远不会 Length(Trim(Sender.AsString))。请参阅我的编辑。 (显示使用正则表达式进行验证的示例的代码也将直接插入该事件处理程序。)引发异常会阻止存储字段内容。您必须编写代码来验证时间是否在允许的范围内,如果不在则引发异常;正则表达式示例也演示了这样做。由于您在标题中添加了 Delphi 7,因此您需要我链接的 TPerlRegEx;也为此添加了示例。
    • 是的,但不幸的是我使用的是 Delphi 7,所以我不能使用正则表达式(而且我认为外部库不太适合任务上下文(它基本上只是一个测试) )。
    猜你喜欢
    • 2016-03-07
    • 2016-09-07
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多