1

我有一个带有几个标记的编辑和单选按钮(分组在单选组中)的表单,供用户输入信息,还有一个保存按钮来保存条目。保存按钮也会关闭表单。如果有无效条目(例如,字母字符而不是数字)或某些条目留空,我想提醒用户更正错误,并且在没有空白编辑框或未选中的单选之前不要关闭表单团体。我通过引发 messageDlg 提醒用户注意错误,分别对每个编辑框和单选组进行错误检查。但是,如果用户没有更正错误并尝试保存表单,我想保持表单打开(无法关闭它)并提醒用户注意错误。只有在所有条目都有效并且没有未经检查的无线电组之后,他才能关闭表单。

根据对我之前消息的一些回复,我编写了以下代码。第一个是一个编辑框的数据输入验证示例(有几个这样的),第二个是我的保存按钮的 OnClick 事件的代码。

procedure TfrmAnalysisOptions.lbleConstraintsMaxChange(Sender: TObject);
var
  I: integer;
  Val, ValidEntry: string;
  Chr: char;
  RangeMin, RangeMax: Double;
  const Allowed = ['0'..'9', '.'];
begin

  Val := lbleConstraintsMax.Text;

      //initialize values    
  ValidEntry := '';
  ConstraintsMaxChange := '';

  //value can contain only numerals, and "."
    for I := 1 to Length(Val) do
     begin
       Chr := Val[I];
       if not (Chr in Allowed) then
       begin
     MessageDlgPos('The value entered for the max value of the ' +
               'constraint must contain only a numeral, a decimal ' +
               'point or a negative sign.',
            mtError, [mbOK], 0, 300, 300);
     Exit;

       end
       else ValidEntry := 'OK'; //validity check for this part

     end;

     //max value cannot be zero or less than the min value
    if not TryStrToFloat(Val, RangeMax) then Exit
    else if RangeMax = 0 then
    begin
       MessageDlg('Max value cannot be zero.', mtError, [mbOK], 0);
       Exit;
    end
    else if not TryStrToFloat(lbleConstraintsMin.Text, RangeMin) then Exit
    else if RangeMax < RangeMin then
      begin
    MessageDlgPos('Max value cannot be less than Min value.',
           mtError, [mbOK], 0, 300, 300);
    Exit;
      end

    else if (RangeMax < 0) then
      begin
    MessageDlgPos('A constraint cannot be negative.',
              mtError, [mbOK], 0, 300, 300);
    Exit;
      end

    //final validity check
    else if ValidEntry = 'OK' then ConstraintsMaxChange := 'OK'
    else MessageDlgPos('There was an unexpected problem with the ' +
               'value entered in the max constraints box.',
            mtError, [mbOK], 0, 300, 300);

end;

这是保存按钮的 OnClick 事件的代码。如您所见,我正在检查多个条目的有效性 - 并且只有当所有条目都有效(即具有“OK”作为相应变量的值)时,我才允许关闭表单。当有无效条目时,它会正确提升 messageDlg。但是,即使在更正错误并按下“保存”按钮后,它仍会继续引发 messageDlg。

procedure TfrmAnalysisOptions.btnSaveOptionsClick(Sender: TObject);
//save input and output options
begin
    //check if all the option questions have been answered
    if not ((ConstraintsMinChange = 'OK') and //validation of correct entry as it is being entered
    (ConstraintsMinExit = 'OK') and //validation of entry as user is moving to another entry after an incorrect entry
    //several other such 'OK's 
      then
      begin
    MessageDlgPos('There is an invalid entry on the form.  Please ' +
              'correct it.', mtError, [mbOK], 0, 300, 300);
    Exit;
      end


    else if //more messageDlgs if some other conditions are not met 

    else
      begin
      //save input and output options
      end;
     //finally if all the conditions are met, close the form 
    Close;
end;
4

3 回答 3

3

将按钮的ModalResult属性设置为mrNone,使其不会自动关闭表单,然后让OnClick事件根据需要验证条目,并ModalResult仅在它们验证确定时才根据需要设置表单的属性,例如:

procedure TfrmAnalysisOptions.btnSaveOptionsClick(Sender: TObject);
begin
  // check the entries as needed ...

  if (there is a validation error) then
  begin
    // do not close this form if there is an invalid entry
    MessageDlgPos('There is an invalid entry.  Please check and correct the entry.', mtError, [mbOK], 0, 300, 300)
    Exit;
  end;

  // save all the entries into different variables ...

  // now close the Form
  ModalResult := mrOk;
end;

更新:根据您的更新,试试这个:

type
  TfrmAnalysisOptions = class(TForm)
  private
    //...
    ConstraintsMinOK: Boolean;
    ConstraintsMaxOK: Boolean;
    //...
  end;

procedure TfrmAnalysisOptions.lbleConstraintsMaxChange(Sender: TObject);
var
  I: integer;
  Val: string;
  Chr: char;
  RangeMin, RangeMax: Double;
begin
  //initialize values    
  ConstraintsMaxOK := False;

  Val := Trim(lbleConstraintsMax.Text);

  if not TryStrToFloat(Val, RangeMax) then
  begin
    MessageDlgPos('The value entered for the max value of the ' +
                  'constraint is not a valid numeric value.',
                  mtError, [mbOK], 0, 300, 300);
    Exit;
  end;

  //max value cannot be zero or less than the min value

  if RangeMax < 0 then
  begin
    MessageDlgPos('The value entered for the max value of the ' +
                  'constraint cannot be negative.',
                  mtError, [mbOK], 0, 300, 300);
    Exit;
  end;

  if RangeMax = 0 then
  begin
    MessageDlg('The value entered for the max value of the ' +
               'constraint cannot be zero.',
               mtError, [mbOK], 0);
    Exit;
  end;

  if not TryStrToFloat(lbleConstraintsMin.Text, RangeMin) then Exit;
  if RangeMax < RangeMin then
  begin
    MessageDlgPos('The value entered for the max value of the ' +
                  'constraint cannot be less than Min value.',
                  mtError, [mbOK], 0, 300, 300);
    Exit;
  end;

  //final validity check
  ConstraintsMaxChange := True;
end;

procedure TfrmAnalysisOptions.btnSaveOptionsClick(Sender: TObject);
begin
  if (not ConstraintsMinOK) or
     (not ConstraintsMaxOK)
    //or several other such 'OK's missing
  then
  begin
    MessageDlgPos('There is an invalid entry on the form.  Please ' +
                  'correct it.', mtError, [mbOK], 0, 300, 300);
    Exit;
  end;

  if //more messageDlgs if some other conditions are not met 
    //...
    Exit;
  end;

  //save input and output options...

  //finally if all the conditions are met, close the form 
  Close;
end;

或者更好的是,不要在用户仍在输入数据时进行动态验证,如果你不小心,可能会导致各种奇怪的副作用。等到按下 Save 按钮,然后验证所有内容:

function ValidateNumeric(const S, Desc: String; var Value: Double): Boolean;
var
  I: Integer;
begin
  Result := TryStrToFloat(Trim(S), Value);
  if not Result then
  begin
    MessageDlgPos('The value entered for the ' + Desc +
                  ' is not a valid numeric value.',
                  mtError, [mbOK], 0, 300, 300);
    Exit;
  end;
end;

procedure TfrmAnalysisOptions.btnSaveOptionsClick(Sender: TObject);
var
  RangeMin, RangeMax: Double;
begin
  if not ValidateNumeric(lbleConstraintsMin.Text, 'min value of the constraint', RangeMin) then
  begin
    lbleConstraintsMin.SetFocus;
    Exit;
  end;

  if not ValidateNumeric(lbleConstraintsMax.Text, 'max value of the constraint', RangeMax) then
  begin
    lbleConstraintsMax.SetFocus;
    Exit;
  end;

  if RangeMax < 0 then
  begin
    MessageDlgPos('The value entered for the max value of the ' +
                  'constraint cannot be negative.',
                  mtError, [mbOK], 0, 300, 300);
    Exit;
  end;

  if RangeMax = 0 then
  begin
    MessageDlg('The value entered for the max value of the ' +
               'constraint cannot be zero.', mtError, [mbOK], 0);
    Exit;
  end;

  if RangeMax < RangeMin then
  begin
    MessageDlgPos('The value entered for the max value of the ' +
                  'constraint cannot be less than Min value.',
                  mtError, [mbOK], 0, 300, 300);
    Exit;
  end;

  //more validations...
  //more messageDlgs if some other conditions are not met ...

  //save input and output options...

  //finally if all the conditions are met, close the form 
  Close;
end;
于 2013-10-09T01:12:27.787 回答
2

这是我们如何处理模态结果和有效性的典型方案:

procedure TSomeModalForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if ModalResult = mrOK then
    begin
      CanClose := CheckValidity;
      if CanClose then
        CanClose := SaveData;
    end
  else if dtsPacket.Modified then
    CanClose := dtsPacket.Cancel
  else if dtsNote.Modified then
    CanClose := dtsNote.Cancel
  else
    CanClose := TRUE;
end;

CheckValidity函数如下所示:

function TSomeModalForm.DoCheckValidity: boolean;
var
  InvCnt: Integer;
begin
  Result := inherited;
  InvCnt := 0;
  //
  HighlightInvalidValue(not edClient.IsEmpty, edClient, InvCnt);
  HighlightInvalidValue(not edBranch.IsEmpty, edBranch, InvCnt);
  HighlightInvalidValue(not edDstClient.IsEmpty, edDstClient, InvCnt);
  HighlightInvalidValue(not edDstBranch.IsEmpty, edDstBranch, InvCnt);
  //
  Result := Result and (InvCnt = 0);
  if not Result then
    ShowInErrBox(1);
end;

该代码基于我们专有的非 VCL 控件,并在表单中假设一些验证支持,但原则应该是显而易见的。

于 2013-10-09T06:26:58.467 回答
1

在你的位置,我会以不同的方式处理这个问题。由于您希望在单击“保存”按钮时执行检查并立即报告任何数据输入问题,因此我将运行一个验证过程,该过程将立即返回所有错误消息。它将允许用户在下次尝试保存之前查看并修复所有问题。

它会是这样的:

在表单中添加一个TMemo组件,使其不可见并对齐为alTop. 此备忘录将保存所有错误消息(如果有)并将显示出来。一个好主意是将所有编辑控件放在面板上并将其对齐为alClient.

保存按钮的OnClick事件处理程序应该是这样的:

procedure TfrmAnalysisOptions.btnSaveOptionsClick(Sender: TObject);
begin
  ErrorsMemo.Lines.Clear; // clear previous messages
  GetErrorMessages(ErrorsMemo.Lines); // run our error check and retrieve messages
  ErrorsMemo.Visible := ErrorsMemo.Lines.Count>0; // if there are messages, show them
  if not ErrorsMemo.Visible then  // if no errors are showing, close
    Close;
end;

GetErrorMessage方法将保存所有检查,并且类似于

procedure TfrmAnalysisOptions.GetErrorMessages(aMessageList: TStrings);
var
  I: Integer;
  Chr: Char;
begin
  // Here you put all the checks and add the error message to aMessageList,
  // for instance:

  // value can contain only numerals, and "."
  for I := 1 to Length(Val) do
  begin
    Chr := Val[I];
    if not (Chr in Allowed) then
      aMessageList.Add('The value entered for the max value of the ' +
                       'constraint must contain only a numeral, a decimal ' +
                       'point or a negative sign.');

 // Other validations follow here...

结尾;

这里的主要思想是将您的检查过程与您的消息呈现分开,并使表单关闭过程更简单。

于 2013-10-10T11:40:57.240 回答