AddButton Caption='增加' 增加一條記錄
ModifyButton Caption='修改' 修改一條記錄
DeleteButton Caption='刪除' 刪除一條記錄
CalcuButton Caption='計算' 計算最終結果並顯示
ExitButton Caption='退出' 系統終止。若當前有打開的文件則先關閉
OpenDialog1 Filter= 選擇或輸入欲打開的文件
'Record File(*.Rec)|.Rec
|Any File(*.*)|*.*'
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
另外,StringGrid1、HazAttr的標題用兩個標簽框(Label)來顯示。
另外我們還需要一個編輯對話框。其中四個編輯框Name、Condition、Nature、 Result分別對應TMethod記錄的四個域。
為協調程序運行,我們定義了一組全局變量。各變量的類型、作用如下表。
表6.2 全局變量及其作用
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
變量名 類型 作用
─────────────────────────────────
MethodFile MethodFileType 與當前打開文件相關聯的文件變量
FileName string[70] 當前打開文件的文件名
Count Count 當前打開文件的記錄總數
CurrentRec Integer 當前處理記錄號
FileOpened Boolean 當前是否有文件打開
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
記錄文件類型MethodFileType的定義為
type
MethodFileType = file of TMethod;
布爾變量FileOpened用於控制文件按鈕的使能、變灰,記錄按鈕的反應以及系統結束時是否需要首先關閉文件。
6.2.3 記錄文件的打開和創建
記錄文件的打開和創建同文本文件一樣也需要關聯和初始化兩個步驟。同文本文件唯一的不同是不能使用Append過程。
記錄文件缺省情況下以讀寫方式打開,如果想以只讀或只寫方式打開,則需要修改System單元中定義的變量FileMode的值。
FileMode的取值和意義如下表。
表6.3 FileMode的取值和意義
━━━━━━━━━━━━━━
取值 意義
──────────────
0 只讀
1 只寫
2 讀寫
━━━━━━━━━━━━━━
FileMode是一個全局變量,對它的每次修改都將影響所有Reset的操作,因此在打開自己的文件後應還原它的值。
在本系統中,當用戶按下“打開”按鈕時,首先彈出一個標准文件打開對話框,要求用戶輸入或選擇文件名。確認後如果該文件名的文件存在,則用Reset打開,若不存在則創建。程序清單如下。
procedure TRecFileForm.OpenButtonClick(Sender: TObject);
begin
if OpenDialog1.Execute then
FileName := OpenDialog1.FileName
else
exit;
AssignFile(MethodFile,Filename);
try
Reset(MethodFile);
FileOpened := True;
except
On EInOutError do
begin
try
if FileExists(FileName) = False then
begin
ReWrite(MethodFile);
FileOpened := True;
end
else
begin
FileOpened := False;
MessageDlg('文件不能打開',mtWarning,[mbOK],0);
end;
except
On EInOutError do
begin
FileOpened := False;
MessageDlg('文件不能創建',mtWarning,[mbOK],0);
end;
end;
end;
end;
if FileOpened = False then exit;
Count := FileSize(MethodFile);
if Count>0 then
ChangeGrid;
RecFileForm.Caption := FormCaption+' -- '+FileName;
NewButton.Enabled := False;
OpenButton.Enabled := False;
CloseButton.Enabled := True;
end;
首先系統試圖用Reset打開一個文件,並置FileOpened為True。如果文件不能打開,則引發一個I/O異常。在異常處理過程中,首先檢測文件是否存在。若不存在則創建這個文件。否則是其它原因引發的異常,則把FileOpend重置為False, 並顯示信息“文件不能打開”。在文件創建過程中仍可能引發異常,因而在一個嵌套的異常處理中把FileOpened重置為False,並提示信息“文件不能創建”。
有關異常處理的內容請讀者參看第十二章。這段程序說明:異常處理機制不僅能使我們的程序更健壯,而且為編程提供了靈活性。
當用戶按下“創建”按鈕時,系統首先彈出一個標准輸入框,要求用戶輸入文件名,確認後系統首先檢測文件是否存在。若存在則直接打開,否則創建一個新文件。打開或創建過程導致異常,則重置FileName和FileOpened兩個全局變量。
procedure TRecFileForm.NewButtonClick(Sender: TObject);
begin
FileName := InputBox('輸入框','請輸入文件名','');
if FileName = '' then Exit;
try
AssignFile(MethodFile,FileName);
if FileExists(FileName) then
begin
Reset(MethodFile);
Count := FileSize(MethodFile);
if Count>0 then
ChangeGrid;
end
else
begin
Rewrite(MethodFile);
count := 0;
end;
FileOpened := true;
Except
on EInOutError do
begin
FileName := '';
FileOpened := False;
end;
end;
if FileOpened then
begin
NewButton.Enabled := False;
OpenButton.Enabled := False;
CloseButton.Enabled := True;
RecFileForm.Caption := FormCaption+' -- '+FileName;
end;
end;
當文件打開或創建後,所要做的工作有:
● 若文件非空,則計算文件長度,並用文件內容填充StringGrid1
● “創建”、“打開”按鈕變灰,“關閉”按鈕使能
● 把文件名附到窗口標題後
6.2.4 記錄文件的讀入和顯示
定義一個全局變量Count用來保存文件中的記錄個數。當文件裝入時:
Count := FileSize(MethodFile);
如果Count > 0,則首先確定StringGrid1的高度、行數。為保證StringGrid1不會覆蓋窗口下面的編輯框,定義一個常量MaxShow。當Count < MaxShow時,記錄可全部顯示;當Count >= MaxShow時,StringGrid1自動添加一個滾動棒。為保證滾動棒不覆蓋掉顯示內容,StringGrid1的寬度應留有余地。
確定StringGrid1高度、行數的代碼如下:
With StringGrid do
if count < MaxShow then
Height := DefaultRowHeight * (Count+1)+10
else
Height := DefaultRowHeight * MaxShow+10;
RowCount := Count+1;
end;
而後從文件中逐個讀入記錄並顯示在StringGrid1的相應位置:
for i := 1 to Count do
begin
Read(MethodFile,MethodRec);
ShowMethod(MethodRec,i);
end;
ShowMehtod是一個過程,用來把一條記錄填入StringGrid1的一行中。對於Name、Condition域而言,只須直接賦值即可;而對Nature 域需要把枚舉類型值轉化為對應意義的字符串(0:“微觀”,1:“宏觀”);而對Result域則需要把數值轉化為一定格式的字符串:
Str (MethodRec.Result:6:4,ResultStr);
StringGrid1.Cells[3,Pos] := ResultStr;
即Result顯示域寬為6,其中小數點後位數為4。
6.2.5 增加一條記錄
當用戶單擊“增加”按鈕時屏幕將會彈出一個記錄編輯模式對話框EditForm。在編輯框中填入合適的內容並按OK鍵關閉後,相應值寫入一個TMethod類型的變量MethodRec中。其中Nature和Result 域需要進行轉換。之後增加的記錄添加到StringGrid1的顯示中。
最後文件定位於尾部,寫入當前記錄,總記錄數加1。
Seek(MethodFile,Count);
Write(MethodFile,MethodRec);
Count := Count+1;
完整的程序清單如下:
procedure TRecFileForm.AddButtonClick(Sender: TObject);
var
MethodRec: TMethod;
Rl: Real;
k: Integer;
EditForm: TEditForm;
begin
if FileOpenEd = False then Exit;
EditForm := TEditForm.Create(self);
if EditForm.ShowModal <> idCancel then
begin
HazAttr.text := '';
MethodRec.Name := EditForm.MethodName.text;
MethodRec.Condition := EditForm.Condition.text;
case EditForm.NatureCombo.ItemIndex of
0:
MethodRec.Nature := Micro;
1:
MethodRec.Nature := Macro ;
end;
Val(EditForm.Result.text,Rl,k);
MethodRec.Result := Rl;
with StringGrid1 do
begin
if Count < MaxShow then
Height := Height+DefaultRowHeight;
RowCount := RowCount+1;
end;
ShowMethod(MethodRec,Count+1);
seek(MethodFile,Count);
write(MethodFile,MethodRec);
Count := Count+1;
end;
end;
6.2.6 修改記錄
首先獲取當前記錄位置:
CurrentRec := StringGrid1.Row - 1;
而後打開編輯對話框並顯示當前值。修改完畢後,修改結果保存在一個記錄中並在StringGrid1中重新顯示。
最後修改結果寫入文件:
Seek(MethodFile,CurrentRec);
Write(MethodFile,MethodRec);
完整程序如下:
procedure TRecFileForm.ModifyButtonClick(Sender: TObject);
var
MethodRec: TMethod;
Rl: Real;
k: Integer;
EditForm: TEditForm;
begin
if FileOpened = False then Exit;
EditForm := TEditForm.Create(self);
CurrentRec := StringGrid1.Row-1;
with EditForm do
begin
MethodName.text := StringGrid1.Cells[0,CurrentRec+1];
Condition.text := StringGrid1.Cells[1,CurrentRec+1];
if StringGrid1.Cells[2,CurrentRec+1] = '微 觀' then
NatureCombo.ItemIndex := 0
else
NatureCombo.ItemIndex := 1;
Result.text := StringGrid1.Cells[3,CurrentRec+1];
if ShowModal <> idCancel then
begin
HazAttr.text := '';
MethodRec.Name := MethodName.text;
MethodRec.Condition := Condition.text;
case NatureCombo.ItemIndex of
0:
MethodRec.Nature := Micro;
1:
MethodRec.Nature := Macro ;
end;
Val(Result.text,Rl,k);
MethodRec.Result := Rl;
ShowMethod(MethodRec,CurrentRec+1);
seek(MethodFile,CurrentRec);
write(MethodFile,MethodRec);
end;
end;
end;
6.2.7 記錄的刪除、插入、排序
刪除一條記錄的基本思路是:獲取當前記錄的位置並把該位置後的記錄逐個向前移動。 文件在最後一條記錄前截斷。
for i:=CurrentRec+1 to Count-1 do
begin
seek(MethodFile,i);
read(MethodFile,MethodRec);
seek(MethodFile,i-1);
Write(MethodFile,MethodRec);
end;
Truncate(MethodFile);
為避免誤刪除,在進行刪除操作前彈出一個消息框進行確認。刪除後要更新全局變量的值和顯示內容:
Count := Count - 1;
ChangeGrid;
完整的程序如下:
procedure TRecFileForm.DeleteButtonClick(Sender: TObject);
var
NewFile: MethodFileType;
MethodRec: TMethod;
NewFileName: String;
i: Integer;
begin
if FileOpened = False then Exit;
CurrentRec := StringGrid1.Row-1;
if CurrentRec < 0 then Exit;
if MessageDlg('Delete Current Record ?', mtConfirmation,
[mbYes, mbNo], 0) = idYes then
begin
HazAttr.text := '';
for I := CurrentRec+1 to Count-1 do
begin
seek(MethodFile,i);
read(MethodFile,MethodRec);
seek(MethodFile,i-1);
Write(MethodFile,MethodRec);
end;
Truncate(MethodFile);
Count := Count-1;
ChangeGrid;
end;
end;
這裡所顯示的刪除操作簡單明了。但在程序開始設計時我卻走了一條彎路,後來發現雖然這種方法用於記錄的刪除操作顯得笨拙、可笑,但卻恰恰是記錄插入、排序的思想。