delphi - 如何从 Delphi 的 Richedit 中获得首次输出?
问题描述
当我的代码输出到富编辑时,我遇到了问题。当我单击按钮计算所有内容然后显示所有内容时,它不会输出生成的 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
创建输出的方法,您会发现它使用了公共sClientNum
字段。
你什么时候真正设置这个变量?它只设置一次,在DatabasePrep
. 所以在你运行之前DatabasePrep
,这个字符串将是空字符串(因为类字段总是被初始化的)。
那么,你什么时候打电话DatabasePrep
?您只能在填充 Rich Edit 控件之后btnCalcClick
调用它。
因此,第一次单击该按钮时,您将获得带有空字符串的输出,而第二次您将获得完整的输出。
您的代码中还有其他问题:
每次创建对象时,都必须保护它以避免内存泄漏:
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
,因此它应该是那里的局部变量。将它作为类字段是危险的,特别是因为在您释放对象而不将指针设置为nil
.在 Microsoft Windows 平台上,换行符序列为 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;
更少的代码更容易阅读和推理。减少愚蠢错别字的风险。
推荐阅读
- java - 如何处理从 org.springframework.security.core.userdetails.User 引发的无效凭据异常
- mysql - 使用 SQL 生成模式
- python - Python 点击命令的功能标志
- android - 每次用户登录领域对象服务器都会创建一个新领域
- sed - Gitlab CI变量问题为页面提取子组路径
- python - Scrapy:如何将 url_id 与抓取的数据一起存储
- docker - 如何在容器内的 debian:stretch 类型的映像中安装 open-ssh 客户端和服务器?
- c# - 我需要模拟输入,为什么 HtmlElement.Focus 不起作用?
- kubernetes - 需要运行复制脚本,将一些文件复制到安装路径 [init-container]
- virtual-reality - 360 度图像在 oculus go 的 a-frame 中开发的 Web 应用程序中显得模糊。如何解决?