文件管理(三)
|
源代码网整理以下2.画出每个自画项目 源代码网整理以下 这在TabSet的OnDrawTab事件处理过程中完成。这一事件处理过程的参数中包含了待画项目索引、画板、待画区域、是否被选中等。这里我们只利用了前三个参数。事实上利用最后一个参数,我们可以对被选中的标签进行一些特殊的视觉效果处理。这一工作就留给读者自己去完成。 源代码网整理以下procedure TFMForm.DriveTabSetDrawTab(Sender: TObject; TabCanvas: TCanvas; 源代码网整理以下R: TRect; Index: Integer; Selected: Boolean); 源代码网整理以下var 软件开发网 www.mscto.com 源代码网整理以下Bitmap: TBitmap; 源代码网整理以下begin 源代码网整理以下Bitmap := TBitmap(DriveTabSet.Tabs.Objects[Index]); 源代码网整理以下with TabCanvas do 软件开发网 www.mscto.com 源代码网整理以下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 :打开或运行一个文件(从文件列表框双击该文件可实现同样效果) 软件开发网 www.mscto.com 源代码网整理以下● Move :文件在不同目录间的移动 源代码网整理以下 ● Copy :文件拷贝 源代码网整理以下 ● Delete :文件删除 源代码网整理以下 ● Rename :文件更名 源代码网整理以下 ● Properties :显示文件属性 软件开发网 www.mscto.com 源代码网整理以下6.4.5.1 文件打开 源代码网整理以下 文件打开功能可以运行一个可执行文件,或把文件在与之相关联的应用程序中打开。文件总是与创建它的应用程序相关联,这种关联可以在Windows的文件管理器中修改。要注意的是:文件的关联是以后缀名为标志的,因而对一个文件关联方式的修改将影响所有相同后缀名的文件。 源代码网整理以下 文件打开功能实现的关键是利用了Windows API函数ShellExecute 。由于Windows API函数的参数要求字符串类型是PChar,而Delphi中一般用的是有结束标志的String类型,因此为调用方便我们把这一函数进行了重新定义如下。 源代码网整理以下function ExecuteFile(const FileName, Params, DefaultDir: String; 源代码网整理以下ShowCmd: Integer): THandle; 软件开发网 www.mscto.com 源代码网整理以下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); 软件开发网 www.mscto.com
源代码网整理以下begin 源代码网整理以下With FileList do 源代码网整理以下begin 源代码网整理以下if HasAttr(FileName,faDirectory) then 源代码网整理以下DirectoryOutline.Directory := FileName 软件开发网 www.mscto.com 源代码网整理以下else 源代码网整理以下ExecuteFile(FileName," " ,Directory,SW_SHOW); 软件开发网 www.mscto.com 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下其中HasAttr是一个fmxutils单元中的自定义函数,用于检测指定文件是否具有某种属性。 源代码网整理以下function HasAttr(const FileName: String; Attr: Word): Boolean; 源代码网整理以下begin 源代码网整理以下Result := (FileGetAttr(FileName) and Attr) = Attr; 软件开发网 www.mscto.com
源代码网整理以下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); 软件开发网 www.mscto.com
源代码网整理以下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 软件开发网 www.mscto.com 源代码网整理以下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; 软件开发网 www.mscto.com 源代码网整理以下 如果我们不使用FileSetDate过程,Windows自动把当前时间作为时间戳写入文件。 源代码网整理以下 文件移动事实上是文件拷贝与文件删除的结合。fmxutils单元中的MoveFile过程实现了这一功能。 源代码网整理以下procedure MoveFile(const FileName, DestName: TFileName); 源代码网整理以下var 源代码网整理以下Destination: TFileName; 源代码网整理以下begin 源代码网整理以下Destination := ExpandFileName(DestName); 源代码网整理以下if not RenameFile(FileName, Destination) then 软件开发网 www.mscto.com
源代码网整理以下begin 源代码网整理以下if HasAttr(FileName, faReadOnly) then 源代码网整理以下raise EFCantMove.Create(Format(SFCantMove, [FileName])); 源代码网整理以下CopyFile(FileName, Destination); 源代码网整理以下DeleteFile(FileName); 软件开发网 www.mscto.com 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下EFCanMove是一个自定义异常类: 源代码网整理以下 type 源代码网整理以下EFCanMove := Class(EStreamError); 源代码网整理以下 有关自定义异常类请参阅第十二章。 源代码网整理以下 文件删除、文件更名直接调用Delphi文件管理过程DeleteFile、RenameFile。它们都以文件名为参数。操作执行前应弹出一个对话框进行确认,执行完毕后应调用Update方法更新FileList的显示。 源代码网整理以下6.4.5.3 一致的界面 源代码网整理以下 文件拷贝、文件移动、 文件更名以及后边的改变当前目录在形式上都表现为从一个源文件到一个目标文件。因而可以采用统一的用户界面,即ChangeForm对话框 源代码网整理以下这四个菜单项共用一个Click事件处理过程,通过对Sender参数的检测,决定将要打开对话框的标题和显示内容。当用户按OK键关闭且目标文件(目录)非空时,程序弹出一个消息对话框要求用户进一步确认,而后执行相应的动作。 源代码网整理以下 共用的事件处理过程FileChange的程序清单如下: 源代码网整理以下procedure TFMForm.FileChange(Sender: TObject); 源代码网整理以下var 源代码网整理以下ChangeForm: TChangeForm; 软件开发网 www.mscto.com 源代码网整理以下IsFile: Boolean; 源代码网整理以下begin 软件开发网 www.mscto.com 源代码网整理以下ChangeForm := TchangeForm.Create(Self); 软件开发网 www.mscto.com 源代码网整理以下IsFile := True; 源代码网整理以下with ChangeForm do 源代码网整理以下begin 软件开发网 www.mscto.com
源代码网整理以下if Sender = Move1 then Caption := "Move" 源代码网整理以下else if Sender = Copy1 then Caption := "Copy" 源代码网整理以下else if Sender = Rename1 then Caption := "Rename" 源代码网整理以下else if Sender = ChangeDirectory1 then 源代码网整理以下begin 源代码网整理以下Caption:="Change Directory"; 源代码网整理以下IsFile:=False; 源代码网整理以下end 源代码网整理以下else Exit; 源代码网整理以下if IsFile then 软件开发网 www.mscto.com
源代码网整理以下begin 软件开发网 www.mscto.com 源代码网整理以下CurrentDir.Caption := FileList.Directory; 源代码网整理以下FromFileName.Text := FileList.FileName; 源代码网整理以下ToFileName.Text := "; 源代码网整理以下end 源代码网整理以下else 源代码网整理以下begin 源代码网整理以下CurrentDir.Caption := DriveTabSet.Tabs[DriveTabSet.TabIndex]; 源代码网整理以下FromFileName.Text := DirectoryOutline.Directory; 源代码网整理以下ToFileName.Text := "; 源代码网整理以下end; 源代码网整理以下if (ShowModal <> idCancel) and (ToFileName.Text <> ") then 源代码网整理以下ConfirmChange(Caption, FromFileName.Text, ToFileName.Text); 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下其中用到的自定义私有过程ConfirmChange用于执行相应的动作: 源代码网整理以下procedure TFMForm.ConfirmChange(const ACaption, FromFile, ToFile: String); 源代码网整理以下begin 源代码网整理以下if MessageDlg(Format("%s %s to %s", [ACaption, FromFile, ToFile]), 源代码网整理以下mtConfirmation, [mbYes, mbNo], 0) = idYes then 源代码网整理以下begin 源代码网整理以下if ACaption = "Move" then 软件开发网 www.mscto.com 源代码网整理以下MoveFile(FromFile, ToFile) 软件开发网 www.mscto.com 源代码网整理以下else if ACaption = "Copy" then 源代码网整理以下CopyFile(FromFile, ToFile) 源代码网整理以下else if ACaption = "Rename" then 源代码网整理以下RenameFile(FromFile, ToFile) 源代码网整理以下else if ACaption = "Change Directory" then 源代码网整理以下changeDirectory(ToFile); 源代码网整理以下FileList.Update; 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下6.4.5.4 显示文件属性 源代码网整理以下 当程序执行Properties 菜单项的Click 事件处理过程时,首先弹出一个TFileAttrForm类型的对话框,显示文件的属性 软件开发网 www.mscto.com
软件开发网 www.mscto.com
源代码网整理以下当用户修改并确认后程序重新设置文件属性。 源代码网整理以下 Properties菜单项的Click事件处理过程如下: 源代码网整理以下procedure TFMForm.Properties1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下Attributes, NewAttributes: Word; 源代码网整理以下FileAttrForm: TFileAttrForm; 源代码网整理以下begin 源代码网整理以下FileAttrForm := TFileAttrForm.Create(self); 源代码网整理以下ShowFileAttr(FileAttrForm,FileList.FileName,FileList.Directory); 源代码网整理以下end; 源代码网整理以下 其中过程ShowFileAttr的实现如下: 源代码网整理以下procedure TFMForm.ShowFileAttr(FileAttrForm:TFileAttrForm; 源代码网整理以下AFileName,Directory:String); 源代码网整理以下var 源代码网整理以下Attributes,NewAttributes: Word; 源代码网整理以下begin 源代码网整理以下with FileAttrForm do 软件开发网 www.mscto.com 源代码网整理以下begin 源代码网整理以下FileName.Caption := AFileName; 源代码网整理以下FilePath.Caption := Directory; 源代码网整理以下ChangeDate.Caption := DateTimeToStr(FileDateTime(AFileName)); 源代码网整理以下Attributes := FileGetAttr(AFileName); 软件开发网 www.mscto.com 源代码网整理以下ReadOnly.Checked := (Attributes and faReadOnly) = faReadOnly; 源代码网整理以下Archive.Checked := (Attributes and faArchive) = faArchive; 源代码网整理以下System.Checked := (Attributes and faSysFile) = faSysFile; 源代码网整理以下Hidden.Checked := (Attributes and faHidden) = faHidden; 软件开发网 www.mscto.com 源代码网整理以下if ShowModal <> idCancel then 源代码网整理以下begin 源代码网整理以下NewAttributes := Attributes; 源代码网整理以下if ReadOnly.Checked then NewAttributes := NewAttributes or faReadOnly 源代码网整理以下else NewAttributes := NewAttributes and not faReadOnly; 源代码网整理以下if Archive.Checked then NewAttributes := NewAttributes or faArchive 源代码网整理以下else NewAttributes := NewAttributes and not faArchive; 源代码网整理以下if System.Checked then NewAttributes := NewAttributes or faSysFile 源代码网整理以下else NewAttributes := NewAttributes and not faSysFile; 源代码网整理以下if Hidden.Checked then NewAttributes := NewAttributes or faHidden 软件开发网 www.mscto.com
源代码网整理以下else NewAttributes := NewAttributes and not faHidden; 源代码网整理以下if NewAttributes <> Attributes then 源代码网整理以下FileSetAttr(AFileName, NewAttributes); 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下以上过程中用到的函数FileDataTime在fmxutils单元中定义,返回一个TDatatime类型的变量。 源代码网整理以下function FileDateTime(const FileName: String): System.TDateTime; 源代码网整理以下begin 源代码网整理以下Result := FileDateToDateTime(FileAge(FileName)); 源代码网整理以下end; 源代码网整理以下6.4.6 其它文件管理功能的实现 源代码网整理以下 在子窗口的Function菜单中,定义了一些其它的文件管理功能: 源代码网整理以下 ● Search :查找一个给定名字的文件,若存在则显示该文件属性 源代码网整理以下 ● Disk View :显示当前驱动器的大小和剩余空间 源代码网整理以下 ● View type :确定显示文件的类型 源代码网整理以下6.4.6.1 文件查找 源代码网整理以下 当用户单击Search菜单项时,程序弹出一个对话框(如图6.10),要求输入待查找的文件名和查找路径。文件名可以是通配符。当用户确认后程序显示第一个匹配文件的属性(如图6.9)。查找不到匹配文件则给出相应的信息。 源代码网整理以下 在实现这一功能的最初设计中,我试图使用FileSearch函数,这个函数允许在多个不同路径中查找。但可惜的是:也许由于系统设计者的失误,这个函数并没有返回它应该返回的东西(第一个匹配文件的全路径名),而是仍把输入的匹配符返回。 源代码网整理以下 没有办法我只能再次使用FindFirst,这个函数的特性在6.3节中已进行了介绍。下面是这一功能的实现代码。 源代码网整理以下procedure TFMForm.search1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下SearchForm: TSearchForm; 源代码网整理以下FileAttrForm: TFileAttrForm; 源代码网整理以下FindIt,path: String; 源代码网整理以下SearchRec: TSearchRec; 源代码网整理以下Return: Integer; 源代码网整理以下begin 源代码网整理以下SearchForm := TSearchForm.Create(self); 源代码网整理以下with SearchForm do 源代码网整理以下begin 源代码网整理以下SearchFile.text := "; 源代码网整理以下SearchPath.text := DirectoryOutline.Directory; 源代码网整理以下if (ShowModal <> idCancel) and 源代码网整理以下(SearchFile.Text <> ") and (SearchPath.text <> ") then 源代码网整理以下begin 源代码网整理以下FindIt := SearchPath.text "" SearchFile.text; 软件开发网 www.mscto.com 源代码网整理以下Return := FindFirst(FindIt,faAnyFile,SearchRec); 源代码网整理以下if Return <> 0 then 源代码网整理以下FindIt := " 源代码网整理以下else 源代码网整理以下FindIt := ExpandFileName(SearchRec.Name); 源代码网整理以下end; 源代码网整理以下if FindIt = " then 源代码网整理以下MessageDlg("Cannot find the file in current directory.", 软件开发网 www.mscto.com 源代码网整理以下mtWarning, [mbOk], 0) 源代码网整理以下else 源代码网整理以下begin 软件开发网 www.mscto.com 源代码网整理以下Path := ExtractFilePath(FindIt); 源代码网整理以下FindIt := ExtractFileName(FindIt); 软件开发网 www.mscto.com
源代码网整理以下FileAttrForm := TFileAttrForm.Create(self); 源代码网整理以下ShowFileAttr(FileAttrForm,FindIt,Path); 源代码网整理以下end; 软件开发网 www.mscto.com 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下6.4.6.2 显示磁盘信息 源代码网整理以下 当用户单击Disk View菜单项时,将弹出一个TDiskViewForm类型的对话框,用来显示当前磁盘的信息 源代码网整理以下 磁盘信息的获取是在DiskViewForm中DriveEdit编辑框的OnChange事件处理过程中实现的。 源代码网整理以下procedure TDiskViewForm.driveEditChange(Sender: TObject); 软件开发网 www.mscto.com 源代码网整理以下var 软件开发网 www.mscto.com 源代码网整理以下dr: Byte; 源代码网整理以下Free,Total: LongInt;[page] 源代码网整理以下begin 源代码网整理以下Free := DiskFree(0); 源代码网整理以下Total := DiskSize(0); 源代码网整理以下FreeSpace.text := IntToStr(Free) " bytes."; 源代码网整理以下TotalSpace.text := IntToStr(Total) " bytes."; 源代码网整理以下end; 软件开发网 www.mscto.com 源代码网整理以下 DiskFree、DiskSize带参数为0表示当前驱动器。读者可以很容易把它改成按用户输入显示磁盘信息的情况。 源代码网整理以下 DiskViewForm中的三个编辑框设计时都令ReadOnly为True。 源代码网整理以下6.4.6.3 改变显示文件的类型 源代码网整理以下 改变显示文件的类型事实上是设置FileList的Mask属性。我们利用一个标准的InputBox输入文件的匹配字符串。而后利用Update方法更新FileList。 源代码网整理以下procedure TFMForm.Viewtype1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下FileMask: String; 源代码网整理以下begin 源代码网整理以下FileMask := InputBox("File type","Input File type For View :",FileList.Mask); 源代码网整理以下If FileMask = " then FileMask := "*.*"; 源代码网整理以下FileList.Mask := FileMask; 源代码网整理以下FileList.Update; 源代码网整理以下CreateCaption; 源代码网整理以下end; 源代码网整理以下 其中的CreateCaption私有过程将在(6.4.8)中进行介绍。 源代码网整理以下6.4.7 目录管理功能的实现 源代码网整理以下 在子窗口的Directory菜单中,提供了目录管理功能: 源代码网整理以下 ● Create Directory :创建一个子目录 源代码网整理以下 ● Delete Directory :删除一个空的子目录 源代码网整理以下 ● Change Directory :改变当前目录 源代码网整理以下6.4.7.1 创建目录 软件开发网 www.mscto.com 源代码网整理以下 创建目录时首先弹出一个TNewDir类型的对话框 源代码网整理以下对话框中要求用户输入目录名。如果用户不输入路径,则缺省认定为当前目录的子目录: 源代码网整理以下 Dir := ExpandFileName(DirName.Text); 源代码网整理以下 而后调用MkDir函数。在目录创建过程中关闭了I/O错误检测,出错不产生异常而是把IOResult设置为非零值。通过检查IOResult是否为0可以确定创建是否成功。 软件开发网 www.mscto.com源代码网整理以下程序清单如下: 源代码网整理以下procedure TFMForm.CreateDirectory1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下NewDir: TNewDir; 源代码网整理以下Dir: String; 源代码网整理以下begin 源代码网整理以下{$I-} 源代码网整理以下NewDir := TNewDir.Create(self); 源代码网整理以下with NewDir do 软件开发网 www.mscto.com 源代码网整理以下begin 源代码网整理以下CurrentDir.Caption := DirectoryOutline.Directory; 源代码网整理以下if (ShowModal <> idCancel) and (DirName.Text <> ") then 源代码网整理以下Dir := ExpandFileName(DirName.text); 源代码网整理以下end; 源代码网整理以下MkDir(Dir); 源代码网整理以下if IOResult <> 0 then 源代码网整理以下MessageDlg("Cannot Create directory", mtWarning, [mbOk], 0); 源代码网整理以下end; 源代码网整理以下 但不幸的是目录创建后我们却无法从当前目录树中看到。必须移到另一个驱动器而后再返回,创建的目录才是可见的。在后边我们将提供一种解决方法。 源代码网整理以下6.4.7.2 删除目录 源代码网整理以下 在实现目录删除过程中,远不如创建目录那么顺利。碰到的问题是: 源代码网整理以下 1.RmDir不允许删除当前目录。但为了操作方便,我们要求删除的恰恰是当前目录; 源代码网整理以下 2.目录删除后调用Refresh方法或Update方法并不能使该目录从屏幕显示中去除。因而当用户试图进入该目录时会导致系统崩溃。 源代码网整理以下 对第一个问题,我们的解决办法是把当前目录转换到其父目录。假如读者记得目录也被操作系统作为一种特殊的文件对待的话,那么就不会对下面的语句感到奇怪了: 源代码网整理以下 path := DirectoryOutline.Directory; 源代码网整理以下 Directoryoutlin.Directory := ExpandFilePath(Path); 软件开发网 www.mscto.com
源代码网整理以下 而后调用RmDir过程: 源代码网整理以下RmDir(Path); 源代码网整理以下 源代码网整理以下 第二个问题的解决却颇为费神。因为DirectoryOutline是Delphi提供的示例部件,没有Help文件支持。通过试验发现:只有当DirectoryOutline的Drive属性改变时,才重新从相应驱动器读取目录。而且它基本上是只读的,除非清除( Clear) 它,象Add、Delete这些方法对它都是无效的。 源代码网整理以下 我曾经考虑过一个笨拙的方法,那就是先改变当前驱动器而后再改回来。但这种方法一方面速度无法忍受,另一方面当只存在一个驱动器可用时会导致系统崩溃。 源代码网整理以下 正当我一筹莫展时,突然想到:DirectoryOutline是一个Sample部件,Delphi 提供了它的源代码。而当我分析了它的源代码后,我知道应该做什么了,那就是为DirectoryOutline增添一个Reset方法! 源代码网整理以下6.7.3 为部件增添一个方法 源代码网整理以下 严格地说,我们所做的工作属于创建一个新部件。但因为我们有源代码,所以不必从DirectoryOutline继承而是直接修改它。这样我们可以省去与创建部件有关的许多繁琐工作。对创建新部件感兴趣的读者可阅读本书第三编的有关章节。 源代码网整理以下 在Delphi IDE中打开DirectoryOutline的源文件后: 源代码网整理以下1.把库单元名改为DirPlus,类名改为TDirectoryOutlinePlus,表明这是DirectoryOutline的增强版。而后存入另一个目录中; 源代码网整理以下 2.添加一个公有方法Reset。这一方法的作用是重新读取当前驱动器的目录。程序清单如下。 软件开发网 www.mscto.com
源代码网整理以下procedure TDirectoryOutlinePlus.Reset; 源代码网整理以下begin 源代码网整理以下ChDir(FDrive ":"); 源代码网整理以下GetDir(0, FDirectory); 源代码网整理以下FDirectory := ForceCase(FDirectory); 源代码网整理以下if not (csLoading in ComponentState) then BuildTree; 源代码网整理以下end; 源代码网整理以下 读者也许被这段代码弄糊涂了。由于篇幅所限,而且涉及到许多自定义部件开发的内容,我们也不准备去详细解释它。假如读者想彻底搞懂它,我建议先看一下本书第三编有关自定义部件开发的内容,而后再对照原DirectoryOutline的源代码进行分析。 源代码网整理以下 3.编译成一个库文件DirPlus.tpu; 源代码网整理以下4.把DirPlus加入部件的Samples页中。 源代码网整理以下 如何添加一个部件见第三编有关章节的介绍。 源代码网整理以下 当增强的目录树准备好以后,必须修改我们的子窗口设计,但却不必亲自修改源代码。 源代码网整理以下 1.删除子窗口中的TDirectoryOutline类部件DirectoryOutline。此时FileList占据了整个客户区; 源代码网整理以下 2.把FileList的Align属改为None,并留出左边的空白供放部件用; 源代码网整理以下 3.在窗口左部加入TDirectoryOutlinPlus类的部件DirectoryOutline; 源代码网整理以下4.把DirectoryOutline的Align属性改为Left,FileList的Align属性还原为Client; 源代码网整理以下5.在DirectoryOutline的事件OnChange列表中选取DirectoryOutlineChange,即原DirectoryOutline的处理过程。 源代码网整理以下 以上工作的最终目标是实现目录创建、删除后屏幕的正确显示。这只需要调用DirectoryOutline的Reset方法即可。 软件开发网 www.mscto.com 源代码网整理以下目录删除过程的实现代码如下。 源代码网整理以下procedure TFMForm.DeleteDirectory1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下path: String; 源代码网整理以下k: Integer; 源代码网整理以下begin 源代码网整理以下{$I-} 源代码网整理以下path := DirectoryOutline.Directory; 源代码网整理以下DirectoryOutline.Directory := ExtractFilePath(Path); 源代码网整理以下if MessageDlg("Delete " path "?", mtConfirmation,[mbYes, mbNo], 0) = idYes then 源代码网整理以下RmDir(path); 源代码网整理以下if IOResult <> 0 then 源代码网整理以下MessageDlg(" Cannot remove directory! The path might not" 源代码网整理以下"exist,non-empty or is the current logged directory.",mtWarning,[mbOk], 0) 源代码网整理以下else 源代码网整理以下DirectoryOutline.Reset; 源代码网整理以下end; 源代码网整理以下修改后的目录创建过程如下。 源代码网整理以下procedure TFMForm.CreateDirectory1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下NewDir: TNewDir; 软件开发网 www.mscto.com
源代码网整理以下Dir: String; 源代码网整理以下begin 源代码网整理以下{$I-} 源代码网整理以下NewDir := TNewDir.Create(self); 源代码网整理以下with NewDir do 源代码网整理以下begin 软件开发网 www.mscto.com 源代码网整理以下CurrentDir.Caption := DirectoryOutline.Directory; 软件开发网 www.mscto.com
源代码网整理以下if (ShowModal <> idCancel) and (DirName.Text <> ") then 软件开发网 www.mscto.com
源代码网整理以下Dir := ExpandFileName(DirName.text); 源代码网整理以下end; 源代码网整理以下MkDir(Dir); 软件开发网 www.mscto.com 源代码网整理以下if IOResult <> 0 then 源代码网整理以下MessageDlg("Cannot Create directory", mtWarning, [mbOk], 0) 源代码网整理以下else 源代码网整理以下DirectoryOutline.Reset; 软件开发网 www.mscto.com 源代码网整理以下end; 源代码网整理以下 当完成了这些工作,把程序重新编译、运行后,可以发现我们所希望实现的功能完全实现了!同时,我们有了一个更好的目录树部件。 源代码网整理以下6.4.7.4 改变当前目录 源代码网整理以下 改变当前目录的实现非常简单,只要修改DirectoryOutline的Directory属性。但需注意的是:当改变后目录所在驱动器也发生变化时应相应修改DriveTabSet的当前值。由于驱动器名与DriveTabSet的索引属性TabIndex之间并没有确定的对应关系,因而需要通过一个循环进行查找匹配。 源代码网整理以下Change Directory的菜单事件处理过程是FileChange,即与文件的移动、拷贝、更名共用一个事件处理过程。详细情况请读者参看(6.4.5.3)中的介绍。 源代码网整理以下改变当前目录的实现如下。 软件开发网 www.mscto.com
源代码网整理以下procedure TFMForm.ChangeDirectory(Todir: String); 软件开发网 www.mscto.com 源代码网整理以下var 源代码网整理以下i: Integer; 源代码网整理以下begin 源代码网整理以下{$I-} 源代码网整理以下ChDir(ToDir); 源代码网整理以下if IOResult <> 0 then 源代码网整理以下MessageDlg("Cannot find directory", mtWarning, [mbOk], 0) 源代码网整理以下else 源代码网整理以下begin 源代码网整理以下with DirectoryOutline do 源代码网整理以下begin 源代码网整理以下Directory := ToDir; 源代码网整理以下Refresh; 源代码网整理以下if DriveTabSet.Tabs[DriveTabSet.TabIndex][1]<>drive then 源代码网整理以下for I := 1 to 25 do 源代码网整理以下if DriveTabSet.Tabs[i][1] = drive then 源代码网整理以下begin 软件开发网 www.mscto.com 源代码网整理以下DriveTabSet.TabIndex := i; 源代码网整理以下Exit; 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下6.4.8 一些问题的处理 源代码网整理以下6.4.8.1 子窗口的标题 源代码网整理以下 Windows的文件管理器是我们设计的楷模,在子窗口显示标题上也不例外。我们把当前目录加上文件的类型作为子窗口的标题。 源代码网整理以下过程CreateCaption用于生成子窗口的标题。 源代码网整理以下procedure TFMForm.CreateCaption; 源代码网整理以下var 源代码网整理以下Cap: String; 源代码网整理以下begin 源代码网整理以下Cap := DirectoryOutline.Directory; 源代码网整理以下Cap := cap "" FileList.mask; 软件开发网 www.mscto.com
源代码网整理以下Caption := Cap; 源代码网整理以下end; 源代码网整理以下 当前目录或文件显示类型发生变化时改变子窗口的标题。如DirectoryOutline的Change事件处理过程和ViewType菜单项的Click事件处理过程就调用了该过程。 源代码网整理以下6.4.8.2 状态条的显示 源代码网整理以下 状态条用于显示当前目录和当前选中文件。它们的值在DirectoryOutline 和FileList的Change事件处理过程中修改。 源代码网整理以下 DirectoryOutline和FileList最终的Change事件处理过程如下: 源代码网整理以下procedure TFMForm.DirectoryOutlineChange(Sender: TObject); 源代码网整理以下begin 源代码网整理以下CreateCaption; 源代码网整理以下FileList.clear; 源代码网整理以下FileList.Directory := DirectoryOutline.Directory; 源代码网整理以下FileList.Update; 源代码网整理以下FileManager.DirectoryPanel.Caption := DirectoryOutline.Directory; 源代码网整理以下end; 软件开发网 www.mscto.com 源代码网整理以下procedure TFMForm.FileListChange(Sender: TObject); 源代码网整理以下begin 软件开发网 www.mscto.com 源代码网整理以下with FileList do 源代码网整理以下begin 源代码网整理以下if (ItemIndex >= 0) and (Not HasAttr(FileName,faDirectory)) then 源代码网整理以下begin 源代码网整理以下TheFileName := FileName; 源代码网整理以下FileManager.FilePanel.Caption := 源代码网整理以下Format("%s, %d bytes", [TheFileName, GetFileSize(TheFileName)]); 源代码网整理以下end 软件开发网 www.mscto.com 源代码网整理以下else 源代码网整理以下FileManager.FilePanel.Caption := "; 源代码网整理以下end; 源代码网整理以下end; 源代码网整理以下6.4.8.3 版本信息 源代码网整理以下 当用户单击主窗口的Help|About菜单项时将弹出一个About对话框,用于显示版本信息(如图6.13)。 源代码网整理以下 这一对话框是用Delphi提供的模板做的。 源代码网整理以下6.4.8.4 菜单项的变灰与使能 源代码网整理以下 File菜单中定义的文件管理功能只有当活动焦点在FileList(即有当前选中文件)时才起作用。否则所有菜单项应变灰,以免导致系统崩溃。 源代码网整理以下 这一功能在File菜单的Click事件处理过程中实现。这一点并不很容易被人想到,希望读者能从中受到启发。 源代码网整理以下procedure TFMForm.File1Click(Sender: TObject); 源代码网整理以下var 源代码网整理以下FileSelected: Boolean; 源代码网整理以下begin 源代码网整理以下FileSelected := FileList.ItemIndex >= 0; 源代码网整理以下Open1.Enabled := FileSelected; 源代码网整理以下Delete1.Enabled := FileSelected; 源代码网整理以下Copy1.Enabled := FileSelected; 源代码网整理以下Move1.Enabled := FileSelected; 源代码网整理以下Rename1.Enabled := FileSelected; 源代码网整理以下Properties1.Enabled := FileSelected; 源代码网整理以下end; 源代码网整理以下 判断是否有文件被选中是通过检测ItemIndex属性是否大于等于0来实现的。 源代码网整理以下 FileSelected := FileList.ItemIndex >= 0; 源代码网整理以下6.4.8.5 可重用的文件处理模块 源代码网整理以下 库单元fmxutils是一个代码库,提供了若干文件处理模块。这些模块除在本程序中使用外,读者可以在其它应用程序中直接调用,而且不必重新编译,只要在Uses子句中包含即可。从中我们可以体会到,Delphi 以库单元为中心的程序组织方式提供了一种较完善的代码重用机制。 源代码网整理以下6.4.9 小结 源代码网整理以下 文件管理器是一个较为综合的例程,使用到了绝大部分以文件名、文件句柄以及其它参数(除文件变量)为操作对象的文件管理过程/函数,同时也提供了一些程序设计开发的思想。我们的介绍是以程序功能模块来组织的,我建议读者在学习并试图自己建立这一程序时采用同样的方法。(6.4.8)中的内容或许是一开始就应了解的,但其它完全可以按顺序逐步地扩充,最后得到一个完整的程序。这一例程在后边的拖放操作和异常处理等章节中还要用到。读者可以以此为基础进一步完善它,使它真正成为一个完全实用的程序。 源代码网整理以下 文件管理是在开发一个高级的Windows程序中不可避免的要涉及到的问题。本章介绍的思路和方法将为读者成为一个熟练的程序员奠定基础。 源代码网推荐 源代码网供稿. |
