'Unable to programmatically close the application when validation error is found - edited

Based on the input from @David, I have edited my post to include more code (the Main procedure and two functions). The problem remains the same:

I want to check if an array of values contains any alpha characters (which would be invalid), and so I pass the values to a function CheckForAlphaInArray from another function called GetYValues. If CheckForAlphaInArray finds an alpha character, I want to alert the user to the invalid character, abort and finally terminate the application so that he can correct the error. The following code does all of it except that it does not close the application. Instead, it moves to the next line in the code. Why is it not closing? I tried using Close and frmMain.Close as well. Did not work.

Thanks.

procedure TfrmMain.actRunExecute(Sender: TObject);
//Run the program using the user-input options in the Analysis Options form
var
  I, K, NumValues, PercentResponse, ConfPercent, PredPercent: integer;
  Header, EstimatedValues, CIHeader_L, CIHeader_U,
  PIHeader_L, PIHeader_U: string;
  C: char;
  EC, HS, SumSqDevX, SumSqDevY, SumCrossProds,
        SumSqDev_YX, MnSumSqDev_YX,
        InputConsMinValue,
        InputConsMaxValue: double;
  InputFile: TStringList;
  X_Array, Y_Array, YHat_Array, SqDevX_Array, SqDevY_Array,
        CrossProds_Array, SD_YX_Array, CILL_Array,
        CIUL_Array, SENewY_Array, PILL_Array, PIUL_Array: TVal_Array;
  MyFile: TextFile;
  const Letters = ['A'..'Z', 'a'..'z', ',', ' '];
  const Numeric = ['0'..'9', ',', ' '];

begin
  ProgressLabel.Caption := '';

  if not (FormSaved = 'Form Saved') then //if user has saved options form
    MessageDlgPos('Please enter and save analysis options first.',
        mtError, [mbOK], 0, 300, 300)
  else
  begin
       Memo1.Clear;
       Gauge1.Progress := 0;
       InputFile := TStringList.Create;
       OutputFile := TStringList.Create;;
       try
     InputFile.LoadFromFile(OpenDialog1.FileName);
    {if data contains a header row, K = 1, else K = 0  }
     //initialize K to an absurd number
     K := 9999;
     Header := InputFile[0];
     for I := 1 to Length(Header) do
       begin
         C := Header[I];
         if CharInSet(C, Letters) then K := 1
         else if CharInSet(C, Numeric) then K := 0;
       end;

     //call error if K has not changed to either 0 or 1
     if (K = 9999) then
       MessageDlgPos('There is an illegal character in the first' +
               'row of your data.  Please fix it.', mtError,
               [mbOK], 0, 300, 300);

     //initialize X and Y arrays
     SetLength(X_Array, InputFile.Count - K);
     SetLength(Y_Array, InputFile.Count - K);

      //Get X and Y values
     X_Array := GetXValues(K, InputFile);
     Gauge1.Progress := 10;
     Y_Array := GetYValues(K, InputFile);
     if (AlphaCharFlag = False) then//from GetYValues function
       begin
         Dialogs.MessageDlg('Exiting the application.', mtInformation,
            [mbOk], 0, mbOk);
         Close;
         Exit;
       end;
     NumValues := Length(X_Array);
     Gauge1.Progress := 20;

     //obtain min and max values for constraints in equation
     InputConsMinValue := -1;
     InputConsMaxValue := -1;
     if (ConstraintsYesNo = 'No') then//from analysis options unit
       begin
         InputConsMinValue := InputConstraintMinValue; //from other unit
         InputConsMaxValue := InputConstraintMaxValue; //from other unit
       end
     else if (ConstraintsYesNo = 'Yes') then
       begin
         InputConsMinValue := MinValue(Y_Array);
         InputConsMaxValue := MaxValue(Y_Array);
       end;


     //obtain iteration range for EC
     EC_Low := -1;
     EC_High := -1;
     if (ECRangeFromData = 'No') then//from analysis options unit
       begin
         EC_Low := IterationRangeMinValue; //from other unit
         EC_High := IterationRangeMaxValue; //from other unit
       end
     else if (ECRangeFromData = 'Yes') then
       begin
         EC_Low := MinValue(X_Array);
         EC_High := MaxValue(X_Array);
       end;

     {Obtain the estimated values of EC and HS as a
      single comma-delimited string }
     EstimatedValues := Estimate(NumValues, InputConsMinValue,
                     InputConsMaxValue, EC_Low, EC_High,
                     X_Array, Y_Array);
     Gauge1.Progress := 50;

     {get the two parameters from the comma delimited string
      result of the Estimate function }
     EC := GetFirstValue(EstimatedValues);
     HS := GetSecondValue(EstimatedValues);
     Gauge1.Progress := 90;

     //Obtain y-hat values
     SetLength(YHat_Array, NumValues);
     YHat_Array := Regress(NumValues, K, X_Array, EC, HS);


     //compute array of SumSq dev from mean for X and Y
     SetLength(SqDevX_Array, NumValues);
     SqDevX_Array := GetSqDevVals(NumValues, X_Array);
     SumSqDevX := Sum(SqDevX_Array);
     SetLength(SqDevY_Array, NumValues);
     SqDevY_Array := GetSqDevVals(NumValues, Y_Array);
     SumSqDevY := Sum(SqDevY_Array);

     //Compute array of sum of products
     SetLength(CrossProds_Array, NumValues);
     CrossProds_Array := GetCrossProds(NumValues, X_Array, Y_Array);
     SumCrossProds := Sum(CrossProds_Array);

     //Compute SumSqDev_YX or Sum(d2_YX) in S&C
     SumSqDev_YX := SumSqDevY - Power(SumCrossProds, 2)/SumSqDevX;

     //Compute Mean SumSqDev_YX (s2_YX in S&C)
     MnSumSqDev_YX := SumSqDev_YX/(NumValues - 2);

     //Compute ResMnSq of predicted population regr line
     SetLength(SD_YX_Array, NumValues);
     SD_YX_Array := GetSD_YX(NumValues, MnSumSqDev_YX,
                  SumSqDevX, SqDevX_Array);

     //Get Confidence Limits
     SetLength(CILL_Array, NumValues);
     CILL_Array := GetConfLL(NumValues, CIPercent, 
                 YHat_Array, SD_YX_Array);
     SetLength(CIUL_Array, NumValues);
     CIUL_Array := GetConfUL(NumValues, CIPercent, 
                 YHat_Array, SD_YX_Array);

     //Compute SE of new Y value
     SetLength(SENewY_Array, NumValues);
     SENewY_Array := GetSENewY(NumValues, MnSumSqDev_YX,
                    SumSqDevX, SqDevX_Array);

     //Get Prediction Limits
     SetLength(PILL_Array, NumValues);
     PILL_Array := GetPredLL(NumValues, PIPercent, 
                 YHat_Array, SENewY_Array);
     SetLength(PIUL_Array, NumValues);
     PIUL_Array := GetPredUL(NumValues, PIPercent, 
                 YHat_Array, SENewY_Array);
     Gauge1.Progress := 100;

     //write output file
     OutputFile.Add('EC = ' + FloatToStr(EC));
     OutputFile.Add('HS = ' + FloatToStr(HS));
     OutputFile.Add('');
     //change headers for CI and PI depending on percent chosen by user
     CIHeader_L := '';
     CIHeader_U := '';
     PIheader_L := '';
     PIheader_U := '';
     if (CIPercent = 90) then
       begin
         CIHeader_L := '90% CI_LL';
         CIHeader_U := '90% CI_UL'
       end
     else if (CIPercent = 95) then
       begin
         CIHeader_L := '95% CI_LL';
         CIHeader_U := '95% CI_UL'
       end
     else if (CIPercent = 99) then
       begin
         CIHeader_L := '99% CI_LL';
         CIHeader_U := '99% CI_UL'
       end;


     if (PIPercent = 90) then
       begin
         PIHeader_L := '90% PI_LL';
         PIHeader_U := '90% PI_UL'
       end
     else if (PIPercent = 95) then
       begin
         PIHeader_L := '95% PI_LL';
         PIHeader_U := '95% PI_UL'
       end
     else if (PIPercent = 99) then
       begin
         PIHeader_L := '99% PI_LL';
         PIHeader_U := '99% PI_UL'
       end;

     OutputFile.Add('X ' + ', ' + 'Y ' + ', ' + 'Y-Hat ' + ', ' +
            CIHeader_L + ', ' + CIHeader_U + ', ' +
            PIHeader_L + ', ' + PIHeader_U);
     for I := 0 to NumValues - 1 do
       OutputFile.Add(FloatToStr(X_Array[I]) + ', ' +
               FloatToStr(Y_Array[I]) + ', ' +
               FloatToStr(YHat_Array[I]) + ', ' +
               FloatToStr(CILL_Array[I])  + ', ' +
               FloatToStr(CIUL_Array[I]) + ', ' +
               FloatToStr(PILL_Array[I]) + ', ' +
               FloatToStr(PIUL_Array[I]));

     //display results in Memo field
     Memo1.Clear;
     Application.ProcessMessages;
     for I := 0 to OutputFile.Count - 1 do
        Memo1.Lines.Add(OutputFile[I]);
     mmuFileSave.Enabled := True;
      finally
    InputFile.Free;
    MessageDlgPos('Done!', mtInformation, [mbOK], 0, 300, 300);
      end;
   end;
end;






//Get Y values in the form of an array
function TfrmMain.GetYValues(K: integer;
  InputFile: TStringList): TVal_Array;
var
  I,J, Posit: integer;
  RowData, Y_Str: string;
  Y_Array: TVal_Array;
  ValidData: Boolean;
  const Letters = ['A'..'Z', 'a'..'z'];
begin
  AlphaCharFlag := True;
  try
    SetLength(Y_Array, InputFile.Count - K);
    try
      //value of K depends on presence/abssence of headers in input file
      for I := K to InputFile.Count-1 do
      begin
    RowData := Trim(InputFile[I]);
    Posit := Pos(',', RowData) - 1;//excluding the comma
    Y_Str := '';
    for J := (Posit+2) to Length(RowData) do Y_Str := Y_Str + RowData[J];
    Y_Str := Trim(Y_Str);
    //check if there are any non-numerical data (letters) in the values
    if not (CheckForAlphaInArray(I, Y_Str)) then
       begin
         AlphaCharFlag := False;
         Exit;
       end;
//        CheckForAlphaInArray(I, Y_Str);
    if (K = 0) then //that is, no header

      begin
        if not TryStrToFloat(Y_Str, Y_Array[I]) then Exit;

      end
    else if (K = 1) then
      begin
        if not TryStrToFloat(Y_Str, Y_Array[I-1]) then Exit;
      end;
      end;
      Result := Y_Array;
      except
    on E: Exception do
       MessageDlgPos('An unexpected error occurred while ' +
              'extracting the Y values from the file. ' +
         E.message, mtError, [mbOK], 0, 300, 300);
      end;
  finally
    Y_Array := nil;
  end;
end;








function TfrmHillSlopeRegr.CheckForAlphaInArray(I: integer; S: string): boolean;
var
  J: integer;
  Chr: char;
  const Numeric = ['0'..'9', '.'];
begin
  for J := 1 to Length(S) do
  begin
    Chr := S[J];
   //if Chr in Numeric then continue else
    if CharInSet(Chr, Numeric) then continue else
    begin
      MessageDlg('Error!  Your file has non-numerical data in row #' +
        IntToStr(I) + '!', mtError, [mbAbort], 0, mbAbort);
      Result := False;
      Exit;
    end;
   end;
   Result := True;
end;

Interestingly, it works fine in the case of a stand-alone application with the following code (that I got from Delphi documentation):

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Dialogs.MessageDlg('Welcome to my Delphi application.  Exit now?',
    mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then
  begin
    Dialogs.MessageDlg('Exiting the Delphi application.', mtInformation,
      [mbOk], 0, mbOk);
    Close;
  end;
end;


Solution 1:[1]

Application.Terminate simply signals the application to start terminating. It doesn't immediately stop the application.

If you want to stop processing the code in your method, just Exit; after calling Application.Terminate; (I've cleaned up the code slightly to remove the unnecessary ValidData variable):

if not (CheckForAlphaInArray(I, Y_Str)) then
begin
  MessageDlg('Exiting the application.', mtInformation, [mbOk], 0, mbOk);
  Application.Terminate;
  Exit;
end;

Solution 2:[2]

Add

Application.ShowMainForm := false;

right above the terminate command

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kromster
Solution 2 Sparky