计算机等级考试二级Delphi辅导知识:文件管理_第6页

考试站(www.examzz.com)   【考试站:中国教育考试第一门户】   2012年12月27日
  定义一个全局变量
   var
   ExitClick: Boolean;
   在子窗口的Exit1Click事件处理过程中:
   ExitClick := True;
   FileManager.Exit1Click(Sender);
   子窗口关闭前可以利用这一全局变量检测是否应关闭:
   If (FileManager.MDIChildCount <= 1) and (Not ExitClick) then
   CanClose := False;
   6.4.3 文件控件的联系
   在本例中我们使用了一组新的控件:TabSet、DirectoryOutline、FileListBox,用于显示和选择驱动器、目录和文件。与(6.3)中所用方法相比,使用这一组控件需要少量的代码支持。
   TabSet与DirectoryOutline的联系在TabSet的Click事件处理过程中建立:
   With DriveTabSet do
   DirectoryOutline.Drive := Tabs[TabIndex][1];
   DirectoryOutline与FileListBox的联系在DirectoryOutline的Change事件处理过程中建立:
   FileList.Directory := DirectoryOutline.Directory;
   FileList.Update;
   6.4.4 DriveTabSet的自画风格显示 
   Dephi为一些控件提供了自画风格的显示,如ListBox、ComboBox、TabSet等。 在缺省情况下,这些控件自动显示文本。而在自画风格下,拥有控件的窗体在运行时间内自己画出控件的每一项目。
   自画风格显示通常的应用是为项目除文本外再添加图形显示。能以自画风格显示的控件有一个共同特点:都拥有一个TStrings类型的项目链。由于TStrings类的特点(参第三章),它们都可以加入一个和对应文本相联系的对象。 而这正是自画风格显示的关键。
   通常情况下产生一个自画风格需要三个步骤:
   1.设置自画风格;
   2.向字符串链表添加图形对象;
   3.画出自画项目。 
   6.4.4.1 设置自画风格 
   控件属性Style 用于设置自画风格。对于DriveTabSet,我们把Style 属性设置为tsOwnerDraw。
   对于ListBox、ComboBox等控件的设置与TabSet略有差异,读者可参阅联机帮助文档。 
   6.4.4.2 向字符串链表添加图形对象 
   1.在应用程序中添加图片部件
   在本程序中我们设置了三个图片部件NetWork、Floppy、Fixed,并分别与三个位图文件NetWork.bmp、Floppy.bmp、Fixed.bmp相关联。
   2.把图片添加到字符串链表中
   根据字符串链表的性质,我们可以把对象与已存在的字符串建立联系,也可以同时添加字符串和对象。这里我们采用后一种方法。
   在子窗口的OnCreate事件处理过程中,我们利用一个循环依次检测从a到z的驱动器是否存在以及驱动器的类型。这利用了Windwos API函数GetDrivetype, 如果驱动器不存在则返回0,否则返回驱动器的类型(DRIVE_REMOVABLE、DRIVE_FIXED、DRIVE_REMOTE)。根据驱动器类型我们可以判断与文本(驱动器名)同时添加到Tabs中的不同图形对象。在添加过程中,DriveTabSet的TabIndex被设置为当前驱动器。
   程序清单如下: 
   procedure TFMForm.FormCreate(Sender: TObject);
   var
   Drive, AddedIndex: Integer;
   DriveLetter: Char;
   begin
   for Drive := 0 to 25 do
   begin
   DriveLetter := Chr(Drive + ord('a'));
   case GetDrivetype(Drive) of
   DRIVE_REMOVABLE:
   AddedIndex := DriveTabSet.Tabs.AddObject(DriveLetter, Floppy.Picture.Graphic);
   DRIVE_FIXED:
   AddedIndex := DriveTabSet.Tabs.AddObject(DriveLetter, Fixed.Picture.Graphic);
   DRIVE_REMOTE:
   AddedIndex := DriveTabSet.Tabs.AddObject(DriveLetter, Network.Picture.Graphic);
   end;
   if UpCase(DriveLetter) = UpCase(FileList.Drive) then
   DriveTabSet.TAbIndex := AddedIndex;
   end;
   end;
   6.4.4.3 画出自画项目 
   当把一个控件的风格设置为自画时,Windows不再负责往屏幕上画出控件的项目,而是为每个可见项目产生自画事件。应用程序可以通过处理自画事件画出控件的项目。 
   1.确定自画项目的大小 
   对于TabSet而言,这在OnMeasureTab事件处理过程中完成。我们需要把DriveTabSet每个标签的宽度增大到足以同时放下文本和位图。 
   procedure TFMForm.DriveTabSetMeasureTab(Sender: TObject; Index: Integer;
   var TabWidth: Integer);
   var
   BitmapWidth: Integer;
   begin
   BitmapWidth := TBitmap(DriveTabSet.Tabs.Objects[Index]).Width;
   Inc(TabWidth, 2 + BitmapWidth);
   end;
   由于TStrings的Objects属性中存放的对象都是TObject类型,并没有Width属性,因而需要再把它转化为TBitmap类型的对象: 
   BitmapWidth := TBitmap(DriveTabSet.Tabs.Objects[Index]).Width;
   2.画出每个自画项目 
   这在TabSet的OnDrawTab事件处理过程中完成。这一事件处理过程的参数中包含了待画项目索引、画板、待画区域、是否被选中等。这里我们只利用了前三个参数。事实上利用最后一个参数,我们可以对被选中的标签进行一些特殊的视觉效果处理。这一工作就留给读者自己去完成。 
   procedure TFMForm.DriveTabSetDrawTab(Sender: TObject; TabCanvas: TCanvas;
   R: TRect; Index: Integer; Selected: Boolean);
   var
   Bitmap: TBitmap;
   begin
   Bitmap := TBitmap(DriveTabSet.Tabs.Objects[Index]);
   with TabCanvas do
   begin
   Draw(R.Left, R.Top + 4, Bitmap);
   TextOut(R.Left + 2 + Bitmap.Width, R.Top + 2, DriveTabSet.Tabs[Index]);
   end;
   end; 
   6.4.5 文件管理基本功能的实现 
   在子窗口的File菜单中,定义了文件管理的基本功能,它们是:
   ● Open :打开或运行一个文件(从文件列表框双击该文件可实现同样效果)
   ● Move :文件在不同目录间的移动
   ● Copy :文件拷贝
   ● Delete :文件删除
   ● Rename :文件更名
   ● Properties :显示文件属性 
   6.4.5.1 文件打开 
   文件打开功能可以运行一个可执行文件,或把文件在与之相关联的应用程序中打开。文件总是与创建它的应用程序相关联,这种关联可以在Windows的文件管理器中修改。要注意的是:文件的关联是以后缀名为标志的,因而对一个文件关联方式的修改将影响所有相同后缀名的文件。
   文件打开功能实现的关键是利用了Windows API函数ShellExecute 。由于Windows API函数的参数要求字符串类型是PChar,而Delphi中一般用的是有结束标志的String类型,因此为调用方便我们把这一函数进行了重新定义如下。 
   function ExecuteFile(const FileName, Params, DefaultDir: String;
   ShowCmd: Integer): THandle;
   var
   zFileName, zParams, zDir: array[0..79] of Char;
   begin
   Result := ShellExecute(Application.MainForm.Handle, nil,
   StrPCopy(zFileName, FileName), StrPCopy(zParams, Params),
   StrPCopy(zDir, DefaultDir), ShowCmd);
   end;
   以上函数在fmxutils单元中定义。fmxutils是一个自定义代码单元。
   有关ShellExecute中各参数的具体含义读者可查阅联机Help文件。
   StrPCopy把一个Pascal类型的字符串拷贝到一个无结束符的PChar类型字符串中。
   在子窗口的Open1Click事件处理过程中: 
   procedure TFMForm.Open1Click(Sender: TObject);
   begin
   with FileList do
   ExecuteFile(FileName, '', Directory, SW_SHOW) ;
   end;
   如果FileList允许显示目录的话(即FileType属性再增加一项ftDirectory),那么对于一个目录而言,打开的含义应该是显示它下边的子目录和文件。程序修改如下。 
   procefure TFMForm.Open1Click(Sender: Tobject);
   begin
   With FileList do
   begin
   if HasAttr(FileName,faDirectory) then
   DirectoryOutline.Directory := FileName
   else
   ExecuteFile(FileName,' ' ,Directory,SW_SHOW);
   end;
   end; 
   其中HasAttr是一个fmxutils单元中的自定义函数,用于检测指定文件是否具有某种属性。 
   function HasAttr(const FileName: String; Attr: Word): Boolean;
   begin
   Result := (FileGetAttr(FileName) and Attr) = Attr;
   end; 
   6.4.5.2 文件拷贝、移动、删除、更名 
   文件拷贝的关键是使用了以文件句柄为操作对象的文件管理函数,因而提供了一种底层的I/O通道。在Object Pascal中这一点是利用无类型文件实现的。
   在文件拷贝中首先检查目标文件名是否是一个目录。如是则把原文件的文件名添加到目标路径后,生成目标文件全路径名。而后提取源文件的时间戳,以备拷贝完成后设置目标文件。拷贝过程中使用了返回文件句柄或以文件句柄为参数的文件管理函数FileOpen、FileCreate、FileRead、FileWrite、FileClose。为保证文件的正常关闭和内存的释放,在拷贝过程中进行异常保护。
   过程CopyFile实现上述功能,它定义在fmxutils单元中。 
   procedure CopyFile(const FileName, DestName: TFileName);
   var
   CopyBuffer: Pointer;
   TimeStamp, BytesCopied: Longint;
   Source, Dest: Integer;
   Destination: TFileName;
   const
   ChunkSize: Longint = 8192;
   begin
   Destination := ExpandFileName(DestName);
   if HasAttr(Destination, faDirectory) then
   Destination := Destination + '\' + ExtractFileName(FileName);
   TimeStamp := FileAge(FileName);
   GetMem(CopyBuffer, ChunkSize);
   try
   Source := FileOpen(FileName, fmShareDenyWrite);
   if Source < 0 then
   raise EFOpenError.Create(FmtLoadStr(SFOpenError, [FileName]));
   try
   Dest := FileCreate(Destination);
   if Dest < 0 then
   raise EFCreateError.Create(FmtLoadStr(SFCreateError,[Destination]));
   try
   repeat
   BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize);
   if BytesCopied > 0 then
   FileWrite(Dest, CopyBuffer^, BytesCopied);
   until BytesCopied < ChunkSize;
   finally
   FileSetDate(Dest,TimeStamp);
   FileClose(Dest);
   end;
   finally
   FileClose(Source);
   end;
   finally
   FreeMem(CopyBuffer, ChunkSize);
   end;
   end;
   如果我们不使用FileSetDate过程,Windows自动把当前时间作为时间戳写入文件。
   文件移动事实上是文件拷贝与文件删除的结合。fmxutils单元中的MoveFile过程实现了这一功能。

相关文章