|
6.2.1 任务介绍 在这一节,我们开发一个系统安全性综合评估方法管理系统。系统安全性在复杂项目开发中十分重要,但由于牵涉面广因而很难获得客观、全面的评估值。鉴于此我们提出多角度、多侧面评估而后定量集成的思路,并在此基础上提出了多种安全性综合评估方法。每种方法由不同部门进行评估而后把结果汇总、综合。 为此我们定义如下的记录类型: type TNature = (Micro,Macro); {方法性质,分为微观和宏观两类} TMethod = Record Name: string[20]; {方法名} Condition: string[40]; {方法适用条件} Nature: TNature; {方法性质} Result: Real; {方法评估值} end; 用来记录不同方法的信息。 由于不同方法的条件、性质不同,因而对工程开发的不同阶段适用方法集也不同。因此需要根据实际情况对方法集进行管理。我们把每一方法作为一条记录,每一方法集作为一个记录文件。下面讨论系统的实现方法。 6.2.2 设计基本思路 本系统要实现的基本功能是文件的打开、创建、关闭、显示,记录的增加、修改、删除以及结果的综合和显示。为此我们使用了两组按钮分别用于文件和记录的操作,使用一个StringGrid控件来显示文件内容,使用一个只读编辑框显示结果的综合。 其中各部件的名称、功能如下表所示: 表6.1 主窗口部件的设计 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 部件名称 主要属性 备注 ────────────────────────────────────── RecFileForm BorderStyle=bsDialog 文件打开后把文件名附到窗口标题后 Position=poScreenCenter StringGrid1 大小行数动态确定 HazAttr(编辑框) ReadOnly=True 显示综合结果 OpenButton TabOrder=0 打开一个记录文件,若文件不存在则创建 NewButton Caption='打开' 创建一个记录文件,若文件存在则打开 CloseButton Caption='关闭' 关闭一个已打开的文件 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;
|