'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 |