如何从 Delphi 中的 richedit 获得首次输出?
How to get first-time output out of a richedit in Delphi?
当我的代码输出到富编辑时出现问题。当我单击按钮计算所有内容然后显示所有内容时,它不会输出生成的 ClientNum 和 Price。但是,当我第二次单击该按钮时,它会毫不费力地输出所有内容吗?我的代码是否有问题,或者可能是某些外部因素(如防病毒软件)干扰了输出?
图片说明我在说什么:
我的代码:
type
TfrmTourBooking = class(TForm)
rgpDestination: TRadioGroup;
rgpAccommodation: TRadioGroup;
sedPeopleAmount: TSpinEdit;
Label1: TLabel;
edtID: TEdit;
Label2: TLabel;
Label3: TLabel;
redOut: TRichEdit;
btnCalc: TButton;
bmbClose: TBitBtn;
rgpTransport: TRadioGroup;
edtName: TEdit;
Label4: TLabel;
rgpTourLength: TRadioGroup;
edtPhoneNum: TLabeledEdit;
edtEmail: TLabeledEdit;
bmbReset: TBitBtn;
dtpTime: TDateTimePicker;
procedure FormActivate(Sender: TObject);
procedure btnCalcClick(Sender: TObject);
procedure rgpDestinationClick(Sender: TObject);
procedure rgpTourLengthClick(Sender: TObject);
procedure rgpAccommodationClick(Sender: TObject);
procedure bmbResetClick(Sender: TObject);
function GetFinalPriceWithVAT : real;
function toString : string;
const
vatRate = 0.15;
private
{ Private declarations }
objGeneralRetrieval:TGenRet;
sDBName,sDBMail,sDBID,sDBPhone,sDBBirth:string;
iDBPeople:integer;
rTranPrice:real;
arrDestinations: array [0..5] of string;
arrDestPrice: array [0..5] of integer;
specialArray: array [1..10] of char;
procedure DatabasePrep;
procedure CasesForRadioGroups;
procedure Validations;
procedure ValidationForPeopleAmount;
procedure ValidationForID;
procedure ValidationForEmail;
procedure ValidationForName;
procedure ValidationForPhoneNum;
procedure ValidationForDOB;
procedure RadioCheck;
public
{ Public declarations }
iPeopleAmount:integer;
sBookName,sID,sPhoneNum,sEmail,sDOB,sDestName:string;
sClientNum:string;
sAccPrint,sTransportPrint,sTLP:string;
rPrelimPrice:real;
rPriceWithVAT:real;
rPrice:real;
end;
var
frmTourBooking: TfrmTourBooking;
implementation
{$R *.dfm}
//this button resets the form
procedure TfrmTourBooking.bmbResetClick(Sender: TObject);
begin
//re-disable the radiogroups
rgpTourLength.Enabled:=False;
rgpTransport.Enabled:=False;
rgpAccommodation.Enabled:=False;
//reset the inputs
edtID.Clear;
dtpTime.Date:=Date;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
rgpDestination.ItemIndex:= -1;
rgpAccommodation.ItemIndex:= -1;
rgpTransport.ItemIndex:= -1;
rgpTourLength.ItemIndex:= -1;
sedPeopleAmount.Value:= 0;
//clear the output
redOut.Clear;
end;
//this button calculates everything and gives an output afterwards
procedure TfrmTourBooking.btnCalcClick(Sender: TObject);
begin
Validations;
CasesForRadioGroups;
redOut.lines.Add(toString);
DatabasePrep;
end;
//validates all the inputs
procedure TfrmTourBooking.Validations;
begin
//people amount check
ValidationForPeopleAmount;
//ID check
ValidationForID;
//Email check
ValidationForEmail;
//Name check
ValidationForName;
//phone number check
ValidationForPhoneNum;
//DOB check
ValidationForDOB;
//if none of the options on the radio groups are checked
RadioCheck;
end;
//the seperate validation procedures
procedure TfrmTourBooking.ValidationForPeopleAmount;
begin
if (sedPeopleAmount.Value < 1) then
begin
ShowMessage('Error: please enter a valid amount of people going on the tour');
//disable the radiogroups
rgpTourLength.Enabled := False;
rgpTransport.Enabled := False;
rgpAccommodation.Enabled := False;
//reset the inputs
edtID.Clear;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
dtpTime.Date:=Date;
rgpDestination.ItemIndex := -1;
rgpAccommodation.ItemIndex := -1;
rgpTransport.ItemIndex := -1;
rgpTourLength.ItemIndex := -1;
sedPeopleAmount.Value := 0;
//clear the output
redOut.Clear;
end;
if (sedPeopleAmount.Value > 30) then
begin
ShowMessage('Error: please enter a valid amount of people going on the tour');
//disable the radiogroups
rgpTourLength.Enabled := False;
rgpTransport.Enabled := False;
rgpAccommodation.Enabled := False;
//reset the inputs
edtID.Clear;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
rgpDestination.ItemIndex := -1;
rgpAccommodation.ItemIndex := -1;
rgpTransport.ItemIndex := -1;
rgpTourLength.ItemIndex := -1;
sedPeopleAmount.Value := 0;
//clear the output
redOut.Clear;
end;
end;
procedure TfrmTourBooking.ValidationForID;
var
iIDLength: integer;
c:char;
i: Integer;
begin
iIDLength := Length(edtID.Text);
//array of special characters
specialArray[1]:= '@';
specialArray[2]:= '!';
specialArray[3]:= '#';
specialArray[4]:= '$';
specialArray[5]:= '%';
specialArray[6]:= '^';
specialArray[7]:= '&';
specialArray[8]:= '*';
specialArray[9]:= '(';
specialArray[10]:= ')';
//end of array
if (iIDLength = 13) then
begin
for c in sID do
begin
for i := 1 to 10 do
begin
if c = specialArray[i] then
begin
ShowMessage('Error: invalid format');
//disable the radiogroups
rgpTourLength.Enabled := False;
rgpTransport.Enabled := False;
rgpAccommodation.Enabled := False;
//reset the inputs
edtID.Clear;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
rgpDestination.ItemIndex := -1;
rgpAccommodation.ItemIndex := -1;
rgpTransport.ItemIndex := -1;
rgpTourLength.ItemIndex := -1;
sedPeopleAmount.Value := 0;
//clear the output
redOut.Clear;
end;
end;
end;
end;
end;
procedure TfrmTourBooking.ValidationForEmail;
begin
end;
procedure TfrmTourBooking.ValidationForName;
begin
end;
procedure TfrmTourBooking.ValidationForPhoneNum;
begin
end;
procedure TfrmTourBooking.ValidationForDOB;
begin
end;
procedure TfrmTourBooking.RadioCheck;
begin
end;
//end of validation procedures
//outputs everything to the rich edit
function TfrmTourBooking.toString : string;
var
firstLine,secondLine,thirdLine,fourthLine,fifthLine:string;
output:string;
begin
iPeopleAmount:= sedPeopleAmount.Value;
sEmail:=edtEmail.Text;
sDOB:=DateToStr(dtpTime.Date);
sBookName:=edtName.Text;
sID:=edtID.Text;
sPhoneNum:=edtPhoneNum.Text;
rPrice:= GetFinalPriceWithVAT;
firstLine:= 'QUOTATION FOR: '+ sClientNum + #13+#13+'Amount of people going on the tour: '+ IntToStr(iPeopleAmount) + #13 + #13 ;
secondLine:='CLIENT DETAILS: '+ #13 + 'Name of booker: '+ sBookName + #13 + 'DOB: ' + sDOB + #13 + 'ID number: '+ sID + #13 + 'Contact Number: '+ sPhoneNum +#13+ 'Email: '+ sEmail + #13 + #13;
thirdLine:= 'TOUR DETAILS: ' + #13 + 'Destination: ' + sDestName + #13 + 'Tour Length: '+ sTLP +#13+ 'Transport type: ' + sTransportPrint + #13 + 'Accomodation: '+ sAccPrint + #13 + #13;
fourthLine:= 'PRICING: ' + #13 + FloatToStrF(rPrice,ffCurrency,6,2)+ #13;
fifthLine:= #13 + '©The Travel Agency 2020';
output:= firstLine + secondLine + thirdLine + fourthLine + fifthLine;
Result:= output;
end;
//this procedure is to handle the nitty gritty of the database input
procedure TfrmTourBooking.DatabasePrep;
begin
//create the object
objGeneralRetrieval := TGenRet.Create(edtName.Text, edtID.Text, edtPhoneNum.Text, sedPeopleAmount.Value, edtEmail.Text);
//get variables for db input from object
sDBName:=objGeneralRetrieval.GetName;
sDBID:=objGeneralRetrieval.GetID;
sDBMail:=objGeneralRetrieval.GetEmail;
sDBPhone:=objGeneralRetrieval.GetPhoneNum;
iDBPeople:=objGeneralRetrieval.GetPeopleAmount;
sDBBirth:=sDOB;
sClientNum := AnsiUpperCase(objGeneralRetrieval.GetClientNum);
//destroy object when done
objGeneralRetrieval.Free;
end;
//this procedure is for the multiple radio groups' outcomes
procedure TfrmTourBooking.CasesForRadioGroups;
var
iBasePrice: Integer;
rMultiplied: Real;
rAdded: Real;
begin
iBasePrice:=0;
rMultiplied:=0;
rAdded:=0;
//the starting prices
arrDestPrice[1]:=4000;
arrDestPrice[2]:=5000;
arrDestPrice[3]:=2500;
arrDestPrice[4]:=3000;
arrDestPrice[5]:=1950;
//when you choose the destination
case (rgpDestination.ItemIndex) of
0:
begin
iBasePrice := arrDestPrice[1];
sDestName := arrDestinations[1];
end;
1:
begin
iBasePrice := arrDestPrice[2];
sDestName := arrDestinations[2];
end;
2:
begin
iBasePrice := arrDestPrice[3];
sDestName := arrDestinations[3];
end;
3:
begin
iBasePrice := arrDestPrice[4];
sDestName := arrDestinations[4];
end;
4:
begin
iBasePrice := arrDestPrice[5];
sDestName := arrDestinations[5];
end;
end;
//When you choose the length of the tour
case (rgpTourLength.ItemIndex) of
0:
begin
rMultiplied := (iBasePrice * 1.5);
sTLP:='3 days';
end;
1:
begin
rMultiplied := (iBasePrice * 2);
sTLP:='5 days';
end;
2:
begin
rMultiplied := (iBasePrice * 2.5);
sTLP:='7 days';
end;
end;
//When you choose the accommodation
case (rgpAccommodation.ItemIndex) of
0:
begin
rAdded := 1500;
sAccPrint:='Hotel';
end;
1:
begin
rAdded := 850;
sAccPrint:='Guesthouse';
end;
2:
begin
rAdded := 0;
sAccPrint:='Own Accommodation';
end;
end;
//When you choose a mode of transport
case (rgpTransport.ItemIndex) of
0:
begin
rTranPrice := 1000;
sTransportPrint:='Bus';
end;
1:
begin
rTranPrice := 3000;
sTransportPrint:='Flight';
end;
2:
begin
rTranPrice := 0;
sTransportPrint:='Own Transport';
end;
end;
rPrelimPrice:= (rMultiplied + rAdded + rTranPrice) * iPeopleAmount;
end;
//to calculate the final price with VAT
function TfrmTourBooking.GetFinalPriceWithVAT : real;
var
vat:real;
begin
vat:= rPrelimPrice * vatRate;
rPriceWithVAT := vat + rPrelimPrice;
Result:= rPriceWithVAT;
end;
//this is when the form starts
procedure TfrmTourBooking.FormActivate(Sender: TObject);
begin
//disable other radio groups than destination at startup
rgpTourLength.Enabled:=False;
rgpAccommodation.Enabled:=False;
rgpTransport.Enabled:=False;
//array initialize
arrDestinations[1]:='Cape Town';
arrDestinations[2]:='Camps Bay';
arrDestinations[3]:='Mossel Bay';
arrDestinations[4]:='Knysna';
arrDestinations[5]:='Oudtshoorn';
//end of array initialize
end;
//these are to disable the radio groups until the previous group is clicked
procedure TfrmTourBooking.rgpAccommodationClick(Sender: TObject);
begin
rgpTransport.Enabled:=True;
end;
procedure TfrmTourBooking.rgpDestinationClick(Sender: TObject);
begin
rgpTourLength.Enabled:=True;
end;
procedure TfrmTourBooking.rgpTourLengthClick(Sender: TObject);
begin
rgpAccommodation.Enabled:=True;
end;
end.
让我们看看您的按钮单击处理程序,它负责填充 Rich Edit 控件:
procedure TfrmTourBooking.btnCalcClick(Sender: TObject);
begin
Validations;
CasesForRadioGroups;
redOut.lines.Add(toString);
DatabasePrep;
end;
如果您查看创建输出的 toString
方法,您会发现它使用了 public sClientNum
字段。
你什么时候真正设置这个变量?它仅在 DatabasePrep
中设置一次。所以在你有 运行 DatabasePrep
之前,这个字符串将是空字符串(因为 class 字段总是被初始化)。
那么,你什么时候打电话给 DatabasePrep
?您只能在 btnCalcClick
、 中调用它,但只能在填充 Rich Edit 控件后调用。
因此,第一次单击该按钮时,您将获得空字符串的输出,而第二次您将获得完整的输出。
您的代码中还有其他问题:
你应该refactor it, especially to avoid repeating yourself。例如,您应该创建一个 ResetForm
方法。
每次创建一个对象,都要对其进行保护,以免内存泄露:
procedure TfrmTourBooking.DatabasePrep;
begin
objGeneralRetrieval := TGenRet.Create(edtName.Text, edtID.Text, edtPhoneNum.Text, sedPeopleAmount.Value, edtEmail.Text);
try
sDBName := objGeneralRetrieval.GetName;
sDBID := objGeneralRetrieval.GetID;
sDBMail := objGeneralRetrieval.GetEmail;
sDBPhone := objGeneralRetrieval.GetPhoneNum;
iDBPeople := objGeneralRetrieval.GetPeopleAmount;
sDBBirth := sDOB;
sClientNum := AnsiUpperCase(objGeneralRetrieval.GetClientNum);
finally
objGeneralRetrieval.Free;
end;
end;
objGeneralRetrieval
变量只在DatabasePrep
中使用,所以应该是那里的局部变量。将它作为 class 字段是很危险的,特别是因为在您释放对象后没有将指针设置为 nil
.
之后它将成为 dangling pointer
在微软Windows平台上,newline sequence是CRLF:#13#10
其他一些提示:
specialArray
应该是常量,不是变量:
const
SpecialChars: array[1..10] of Char = '@!#$%^&*()';
当你迭代这个数组时,你会做 for i := 1 to 10 do
。但是,如果您添加了一个新的特殊字符而忘记更新此 for
循环行怎么办?最好做 for i := Low(SpecialChars) to High(SpecialChars)
。更好的是使用 for..in
循环。
此代码:
case (rgpDestination.ItemIndex) of
0:
begin
iBasePrice := arrDestPrice[1];
sDestName := arrDestinations[1];
end;
1:
begin
iBasePrice := arrDestPrice[2];
sDestName := arrDestinations[2];
end;
2:
begin
iBasePrice := arrDestPrice[3];
sDestName := arrDestinations[3];
end;
3:
begin
iBasePrice := arrDestPrice[4];
sDestName := arrDestinations[4];
end;
4:
begin
iBasePrice := arrDestPrice[5];
sDestName := arrDestinations[5];
end;
end;
可以写得更简洁:
if rgpDestination.ItemIndex <> -1 then
begin
iBasePrice := arrDestPrice[rgpDestination.ItemIndex + 1];
sDestName := arrDestinations[rgpDestination.ItemIndex + 1];
end;
更少的代码更易于阅读和推理。减少愚蠢错别字的风险。
当我的代码输出到富编辑时出现问题。当我单击按钮计算所有内容然后显示所有内容时,它不会输出生成的 ClientNum 和 Price。但是,当我第二次单击该按钮时,它会毫不费力地输出所有内容吗?我的代码是否有问题,或者可能是某些外部因素(如防病毒软件)干扰了输出?
图片说明我在说什么:
我的代码:
type
TfrmTourBooking = class(TForm)
rgpDestination: TRadioGroup;
rgpAccommodation: TRadioGroup;
sedPeopleAmount: TSpinEdit;
Label1: TLabel;
edtID: TEdit;
Label2: TLabel;
Label3: TLabel;
redOut: TRichEdit;
btnCalc: TButton;
bmbClose: TBitBtn;
rgpTransport: TRadioGroup;
edtName: TEdit;
Label4: TLabel;
rgpTourLength: TRadioGroup;
edtPhoneNum: TLabeledEdit;
edtEmail: TLabeledEdit;
bmbReset: TBitBtn;
dtpTime: TDateTimePicker;
procedure FormActivate(Sender: TObject);
procedure btnCalcClick(Sender: TObject);
procedure rgpDestinationClick(Sender: TObject);
procedure rgpTourLengthClick(Sender: TObject);
procedure rgpAccommodationClick(Sender: TObject);
procedure bmbResetClick(Sender: TObject);
function GetFinalPriceWithVAT : real;
function toString : string;
const
vatRate = 0.15;
private
{ Private declarations }
objGeneralRetrieval:TGenRet;
sDBName,sDBMail,sDBID,sDBPhone,sDBBirth:string;
iDBPeople:integer;
rTranPrice:real;
arrDestinations: array [0..5] of string;
arrDestPrice: array [0..5] of integer;
specialArray: array [1..10] of char;
procedure DatabasePrep;
procedure CasesForRadioGroups;
procedure Validations;
procedure ValidationForPeopleAmount;
procedure ValidationForID;
procedure ValidationForEmail;
procedure ValidationForName;
procedure ValidationForPhoneNum;
procedure ValidationForDOB;
procedure RadioCheck;
public
{ Public declarations }
iPeopleAmount:integer;
sBookName,sID,sPhoneNum,sEmail,sDOB,sDestName:string;
sClientNum:string;
sAccPrint,sTransportPrint,sTLP:string;
rPrelimPrice:real;
rPriceWithVAT:real;
rPrice:real;
end;
var
frmTourBooking: TfrmTourBooking;
implementation
{$R *.dfm}
//this button resets the form
procedure TfrmTourBooking.bmbResetClick(Sender: TObject);
begin
//re-disable the radiogroups
rgpTourLength.Enabled:=False;
rgpTransport.Enabled:=False;
rgpAccommodation.Enabled:=False;
//reset the inputs
edtID.Clear;
dtpTime.Date:=Date;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
rgpDestination.ItemIndex:= -1;
rgpAccommodation.ItemIndex:= -1;
rgpTransport.ItemIndex:= -1;
rgpTourLength.ItemIndex:= -1;
sedPeopleAmount.Value:= 0;
//clear the output
redOut.Clear;
end;
//this button calculates everything and gives an output afterwards
procedure TfrmTourBooking.btnCalcClick(Sender: TObject);
begin
Validations;
CasesForRadioGroups;
redOut.lines.Add(toString);
DatabasePrep;
end;
//validates all the inputs
procedure TfrmTourBooking.Validations;
begin
//people amount check
ValidationForPeopleAmount;
//ID check
ValidationForID;
//Email check
ValidationForEmail;
//Name check
ValidationForName;
//phone number check
ValidationForPhoneNum;
//DOB check
ValidationForDOB;
//if none of the options on the radio groups are checked
RadioCheck;
end;
//the seperate validation procedures
procedure TfrmTourBooking.ValidationForPeopleAmount;
begin
if (sedPeopleAmount.Value < 1) then
begin
ShowMessage('Error: please enter a valid amount of people going on the tour');
//disable the radiogroups
rgpTourLength.Enabled := False;
rgpTransport.Enabled := False;
rgpAccommodation.Enabled := False;
//reset the inputs
edtID.Clear;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
dtpTime.Date:=Date;
rgpDestination.ItemIndex := -1;
rgpAccommodation.ItemIndex := -1;
rgpTransport.ItemIndex := -1;
rgpTourLength.ItemIndex := -1;
sedPeopleAmount.Value := 0;
//clear the output
redOut.Clear;
end;
if (sedPeopleAmount.Value > 30) then
begin
ShowMessage('Error: please enter a valid amount of people going on the tour');
//disable the radiogroups
rgpTourLength.Enabled := False;
rgpTransport.Enabled := False;
rgpAccommodation.Enabled := False;
//reset the inputs
edtID.Clear;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
rgpDestination.ItemIndex := -1;
rgpAccommodation.ItemIndex := -1;
rgpTransport.ItemIndex := -1;
rgpTourLength.ItemIndex := -1;
sedPeopleAmount.Value := 0;
//clear the output
redOut.Clear;
end;
end;
procedure TfrmTourBooking.ValidationForID;
var
iIDLength: integer;
c:char;
i: Integer;
begin
iIDLength := Length(edtID.Text);
//array of special characters
specialArray[1]:= '@';
specialArray[2]:= '!';
specialArray[3]:= '#';
specialArray[4]:= '$';
specialArray[5]:= '%';
specialArray[6]:= '^';
specialArray[7]:= '&';
specialArray[8]:= '*';
specialArray[9]:= '(';
specialArray[10]:= ')';
//end of array
if (iIDLength = 13) then
begin
for c in sID do
begin
for i := 1 to 10 do
begin
if c = specialArray[i] then
begin
ShowMessage('Error: invalid format');
//disable the radiogroups
rgpTourLength.Enabled := False;
rgpTransport.Enabled := False;
rgpAccommodation.Enabled := False;
//reset the inputs
edtID.Clear;
edtName.Clear;
edtPhoneNum.Clear;
edtEmail.Clear;
rgpDestination.ItemIndex := -1;
rgpAccommodation.ItemIndex := -1;
rgpTransport.ItemIndex := -1;
rgpTourLength.ItemIndex := -1;
sedPeopleAmount.Value := 0;
//clear the output
redOut.Clear;
end;
end;
end;
end;
end;
procedure TfrmTourBooking.ValidationForEmail;
begin
end;
procedure TfrmTourBooking.ValidationForName;
begin
end;
procedure TfrmTourBooking.ValidationForPhoneNum;
begin
end;
procedure TfrmTourBooking.ValidationForDOB;
begin
end;
procedure TfrmTourBooking.RadioCheck;
begin
end;
//end of validation procedures
//outputs everything to the rich edit
function TfrmTourBooking.toString : string;
var
firstLine,secondLine,thirdLine,fourthLine,fifthLine:string;
output:string;
begin
iPeopleAmount:= sedPeopleAmount.Value;
sEmail:=edtEmail.Text;
sDOB:=DateToStr(dtpTime.Date);
sBookName:=edtName.Text;
sID:=edtID.Text;
sPhoneNum:=edtPhoneNum.Text;
rPrice:= GetFinalPriceWithVAT;
firstLine:= 'QUOTATION FOR: '+ sClientNum + #13+#13+'Amount of people going on the tour: '+ IntToStr(iPeopleAmount) + #13 + #13 ;
secondLine:='CLIENT DETAILS: '+ #13 + 'Name of booker: '+ sBookName + #13 + 'DOB: ' + sDOB + #13 + 'ID number: '+ sID + #13 + 'Contact Number: '+ sPhoneNum +#13+ 'Email: '+ sEmail + #13 + #13;
thirdLine:= 'TOUR DETAILS: ' + #13 + 'Destination: ' + sDestName + #13 + 'Tour Length: '+ sTLP +#13+ 'Transport type: ' + sTransportPrint + #13 + 'Accomodation: '+ sAccPrint + #13 + #13;
fourthLine:= 'PRICING: ' + #13 + FloatToStrF(rPrice,ffCurrency,6,2)+ #13;
fifthLine:= #13 + '©The Travel Agency 2020';
output:= firstLine + secondLine + thirdLine + fourthLine + fifthLine;
Result:= output;
end;
//this procedure is to handle the nitty gritty of the database input
procedure TfrmTourBooking.DatabasePrep;
begin
//create the object
objGeneralRetrieval := TGenRet.Create(edtName.Text, edtID.Text, edtPhoneNum.Text, sedPeopleAmount.Value, edtEmail.Text);
//get variables for db input from object
sDBName:=objGeneralRetrieval.GetName;
sDBID:=objGeneralRetrieval.GetID;
sDBMail:=objGeneralRetrieval.GetEmail;
sDBPhone:=objGeneralRetrieval.GetPhoneNum;
iDBPeople:=objGeneralRetrieval.GetPeopleAmount;
sDBBirth:=sDOB;
sClientNum := AnsiUpperCase(objGeneralRetrieval.GetClientNum);
//destroy object when done
objGeneralRetrieval.Free;
end;
//this procedure is for the multiple radio groups' outcomes
procedure TfrmTourBooking.CasesForRadioGroups;
var
iBasePrice: Integer;
rMultiplied: Real;
rAdded: Real;
begin
iBasePrice:=0;
rMultiplied:=0;
rAdded:=0;
//the starting prices
arrDestPrice[1]:=4000;
arrDestPrice[2]:=5000;
arrDestPrice[3]:=2500;
arrDestPrice[4]:=3000;
arrDestPrice[5]:=1950;
//when you choose the destination
case (rgpDestination.ItemIndex) of
0:
begin
iBasePrice := arrDestPrice[1];
sDestName := arrDestinations[1];
end;
1:
begin
iBasePrice := arrDestPrice[2];
sDestName := arrDestinations[2];
end;
2:
begin
iBasePrice := arrDestPrice[3];
sDestName := arrDestinations[3];
end;
3:
begin
iBasePrice := arrDestPrice[4];
sDestName := arrDestinations[4];
end;
4:
begin
iBasePrice := arrDestPrice[5];
sDestName := arrDestinations[5];
end;
end;
//When you choose the length of the tour
case (rgpTourLength.ItemIndex) of
0:
begin
rMultiplied := (iBasePrice * 1.5);
sTLP:='3 days';
end;
1:
begin
rMultiplied := (iBasePrice * 2);
sTLP:='5 days';
end;
2:
begin
rMultiplied := (iBasePrice * 2.5);
sTLP:='7 days';
end;
end;
//When you choose the accommodation
case (rgpAccommodation.ItemIndex) of
0:
begin
rAdded := 1500;
sAccPrint:='Hotel';
end;
1:
begin
rAdded := 850;
sAccPrint:='Guesthouse';
end;
2:
begin
rAdded := 0;
sAccPrint:='Own Accommodation';
end;
end;
//When you choose a mode of transport
case (rgpTransport.ItemIndex) of
0:
begin
rTranPrice := 1000;
sTransportPrint:='Bus';
end;
1:
begin
rTranPrice := 3000;
sTransportPrint:='Flight';
end;
2:
begin
rTranPrice := 0;
sTransportPrint:='Own Transport';
end;
end;
rPrelimPrice:= (rMultiplied + rAdded + rTranPrice) * iPeopleAmount;
end;
//to calculate the final price with VAT
function TfrmTourBooking.GetFinalPriceWithVAT : real;
var
vat:real;
begin
vat:= rPrelimPrice * vatRate;
rPriceWithVAT := vat + rPrelimPrice;
Result:= rPriceWithVAT;
end;
//this is when the form starts
procedure TfrmTourBooking.FormActivate(Sender: TObject);
begin
//disable other radio groups than destination at startup
rgpTourLength.Enabled:=False;
rgpAccommodation.Enabled:=False;
rgpTransport.Enabled:=False;
//array initialize
arrDestinations[1]:='Cape Town';
arrDestinations[2]:='Camps Bay';
arrDestinations[3]:='Mossel Bay';
arrDestinations[4]:='Knysna';
arrDestinations[5]:='Oudtshoorn';
//end of array initialize
end;
//these are to disable the radio groups until the previous group is clicked
procedure TfrmTourBooking.rgpAccommodationClick(Sender: TObject);
begin
rgpTransport.Enabled:=True;
end;
procedure TfrmTourBooking.rgpDestinationClick(Sender: TObject);
begin
rgpTourLength.Enabled:=True;
end;
procedure TfrmTourBooking.rgpTourLengthClick(Sender: TObject);
begin
rgpAccommodation.Enabled:=True;
end;
end.
让我们看看您的按钮单击处理程序,它负责填充 Rich Edit 控件:
procedure TfrmTourBooking.btnCalcClick(Sender: TObject);
begin
Validations;
CasesForRadioGroups;
redOut.lines.Add(toString);
DatabasePrep;
end;
如果您查看创建输出的 toString
方法,您会发现它使用了 public sClientNum
字段。
你什么时候真正设置这个变量?它仅在 DatabasePrep
中设置一次。所以在你有 运行 DatabasePrep
之前,这个字符串将是空字符串(因为 class 字段总是被初始化)。
那么,你什么时候打电话给 DatabasePrep
?您只能在 btnCalcClick
、 中调用它,但只能在填充 Rich Edit 控件后调用。
因此,第一次单击该按钮时,您将获得空字符串的输出,而第二次您将获得完整的输出。
您的代码中还有其他问题:
你应该refactor it, especially to avoid repeating yourself。例如,您应该创建一个
ResetForm
方法。每次创建一个对象,都要对其进行保护,以免内存泄露:
procedure TfrmTourBooking.DatabasePrep; begin objGeneralRetrieval := TGenRet.Create(edtName.Text, edtID.Text, edtPhoneNum.Text, sedPeopleAmount.Value, edtEmail.Text); try sDBName := objGeneralRetrieval.GetName; sDBID := objGeneralRetrieval.GetID; sDBMail := objGeneralRetrieval.GetEmail; sDBPhone := objGeneralRetrieval.GetPhoneNum; iDBPeople := objGeneralRetrieval.GetPeopleAmount; sDBBirth := sDOB; sClientNum := AnsiUpperCase(objGeneralRetrieval.GetClientNum); finally objGeneralRetrieval.Free; end; end;
之后它将成为 dangling pointerobjGeneralRetrieval
变量只在DatabasePrep
中使用,所以应该是那里的局部变量。将它作为 class 字段是很危险的,特别是因为在您释放对象后没有将指针设置为nil
.在微软Windows平台上,newline sequence是CRLF:
#13#10
其他一些提示:
specialArray
应该是常量,不是变量:const SpecialChars: array[1..10] of Char = '@!#$%^&*()';
当你迭代这个数组时,你会做
for i := 1 to 10 do
。但是,如果您添加了一个新的特殊字符而忘记更新此for
循环行怎么办?最好做for i := Low(SpecialChars) to High(SpecialChars)
。更好的是使用for..in
循环。此代码:
case (rgpDestination.ItemIndex) of 0: begin iBasePrice := arrDestPrice[1]; sDestName := arrDestinations[1]; end; 1: begin iBasePrice := arrDestPrice[2]; sDestName := arrDestinations[2]; end; 2: begin iBasePrice := arrDestPrice[3]; sDestName := arrDestinations[3]; end; 3: begin iBasePrice := arrDestPrice[4]; sDestName := arrDestinations[4]; end; 4: begin iBasePrice := arrDestPrice[5]; sDestName := arrDestinations[5]; end; end;
可以写得更简洁:
if rgpDestination.ItemIndex <> -1 then begin iBasePrice := arrDestPrice[rgpDestination.ItemIndex + 1]; sDestName := arrDestinations[rgpDestination.ItemIndex + 1]; end;
更少的代码更易于阅读和推理。减少愚蠢错别字的风险。