6.4.7.1 創(chuàng)建目錄
創(chuàng)建目錄時(shí)首先彈出一個(gè)TNewDir類型的對話框
對話框中要求用戶輸入目錄名。如果用戶不輸入路徑,則缺省認(rèn)定為當(dāng)前目錄的子目錄:
Dir := ExpandFileName(DirName.Text);
而后調(diào)用MkDir函數(shù)。在目錄創(chuàng)建過程中關(guān)閉了I/O錯(cuò)誤檢測,出錯(cuò)不產(chǎn)生異常而是把IOResult設(shè)置為非零值。通過檢查IOResult是否為0可以確定創(chuàng)建是否成功。
程序清單如下:
procedure TFMForm.CreateDirectory1Click(Sender: TObject);
var
NewDir: TNewDir;
Dir: String;
begin
{$I-}
NewDir := TNewDir.Create(self);
with NewDir do
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;
但不幸的是目錄創(chuàng)建后我們卻無法從當(dāng)前目錄樹中看到。必須移到另一個(gè)驅(qū)動(dòng)器而后再返回,創(chuàng)建的目錄才是可見的。在后邊我們將提供一種解決方法。
6.4.7.2 刪除目錄
在實(shí)現(xiàn)目錄刪除過程中,遠(yuǎn)不如創(chuàng)建目錄那么順利。碰到的問題是:
1.RmDir不允許刪除當(dāng)前目錄。但為了操作方便,我們要求刪除的恰恰是當(dāng)前目錄;
2.目錄刪除后調(diào)用Refresh方法或Update方法并不能使該目錄從屏幕顯示中去除。因而當(dāng)用戶試圖進(jìn)入該目錄時(shí)會(huì)導(dǎo)致系統(tǒng)崩潰。
對第一個(gè)問題,我們的解決辦法是把當(dāng)前目錄轉(zhuǎn)換到其父目錄。假如讀者記得目錄也被操作系統(tǒng)作為一種特殊的文件對待的話,那么就不會(huì)對下面的語句感到奇怪了:
path := DirectoryOutline.Directory;
Directoryoutlin.Directory := ExpandFilePath(Path);
而后調(diào)用RmDir過程:
RmDir(Path);
第二個(gè)問題的解決卻頗為費(fèi)神。因?yàn)镈irectoryOutline是Delphi提供的示例部件,沒有Help文件支持。通過試驗(yàn)發(fā)現(xiàn):只有當(dāng)DirectoryOutline的Drive屬性改變時(shí),才重新從相應(yīng)驅(qū)動(dòng)器讀取目錄。而且它基本上是只讀的,除非清除( Clear) 它,象Add、Delete這些方法對它都是無效的。
我曾經(jīng)考慮過一個(gè)笨拙的方法,那就是先改變當(dāng)前驅(qū)動(dòng)器而后再改回來。但這種方法一方面速度無法忍受,另一方面當(dāng)只存在一個(gè)驅(qū)動(dòng)器可用時(shí)會(huì)導(dǎo)致系統(tǒng)崩潰。
正當(dāng)我一籌莫展時(shí),突然想到:DirectoryOutline是一個(gè)Sample部件,Delphi 提供了它的源代碼。而當(dāng)我分析了它的源代碼后,我知道應(yīng)該做什么了,那就是為DirectoryOutline增添一個(gè)Reset方法!
6.4.7.3 為部件增添一個(gè)方法
嚴(yán)格地說,我們所做的工作屬于創(chuàng)建一個(gè)新部件。但因?yàn)槲覀冇性创a,所以不必從DirectoryOutline繼承而是直接修改它。這樣我們可以省去與創(chuàng)建部件有關(guān)的許多繁瑣工作。對創(chuàng)建新部件感興趣的讀者可閱讀本書第三編的有關(guān)章節(jié)。
在Delphi IDE中打開DirectoryOutline的源文件后:
1.把庫單元名改為DirPlus,類名改為TDirectoryOutlinePlus,表明這是DirectoryOutline的增強(qiáng)版。而后存入另一個(gè)目錄中;
2.添加一個(gè)公有方法Reset。這一方法的作用是重新讀取當(dāng)前驅(qū)動(dòng)器的目錄。程序清單如下。
procedure TDirectoryOutlinePlus.Reset;
begin
ChDir(FDrive + ':');
GetDir(0, FDirectory);
FDirectory := ForceCase(FDirectory);
if not (csLoading in ComponentState) then BuildTree;
end;
讀者也許被這段代碼弄糊涂了。由于篇幅所限,而且涉及到許多自定義部件開發(fā)的內(nèi)容,我們也不準(zhǔn)備去詳細(xì)解釋它。假如讀者想徹底搞懂它,我建議先看一下本書第三編有關(guān)自定義部件開發(fā)的內(nèi)容,而后再對照原DirectoryOutline的源代碼進(jìn)行分析。
3.編譯成一個(gè)庫文件DirPlus.tpu;
4.把DirPlus加入部件的Samples頁中。
如何添加一個(gè)部件見第三編有關(guān)章節(jié)的介紹。
當(dāng)增強(qiáng)的目錄樹準(zhǔn)備好以后,必須修改我們的子窗口設(shè)計(jì),但卻不必親自修改源代碼。
1.刪除子窗口中的TDirectoryOutline類部件DirectoryOutline。此時(shí)FileList占據(jù)了整個(gè)客戶區(qū);
2.把FileList的Align屬改為None,并留出左邊的空白供放部件用;
3.在窗口左部加入TDirectoryOutlinPlus類的部件DirectoryOutline;
4.把DirectoryOutline的Align屬性改為Left,F(xiàn)ileList的Align屬性還原為Client;
5.在DirectoryOutline的事件OnChange列表中選取DirectoryOutlineChange,即原DirectoryOutline的處理過程。
以上工作的最終目標(biāo)是實(shí)現(xiàn)目錄創(chuàng)建、刪除后屏幕的正確顯示。這只需要調(diào)用DirectoryOutline的Reset方法即可。
目錄刪除過程的實(shí)現(xiàn)代碼如下。
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;
修改后的目錄創(chuàng)建過程如下。
procedure TFMForm.CreateDirectory1Click(Sender: TObject);
var
NewDir: TNewDir;
Dir: String;
begin
{$I-}
NewDir := TNewDir.Create(self);
with NewDir do
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)
else
DirectoryOutline.Reset;
end;
當(dāng)完成了這些工作,把程序重新編譯、運(yùn)行后,可以發(fā)現(xiàn)我們所希望實(shí)現(xiàn)的功能完全實(shí)現(xiàn)了!同時(shí),我們有了一個(gè)更好的目錄樹部件。
6.4.7.4 改變當(dāng)前目錄
改變當(dāng)前目錄的實(shí)現(xiàn)非常簡單,只要修改DirectoryOutline的Directory屬性。但需注意的是:當(dāng)改變后目錄所在驅(qū)動(dòng)器也發(fā)生變化時(shí)應(yīng)相應(yīng)修改DriveTabSet的當(dāng)前值。由于驅(qū)動(dòng)器名與DriveTabSet的索引屬性TabIndex之間并沒有確定的對應(yīng)關(guān)系,因而需要通過一個(gè)循環(huán)進(jìn)行查找匹配。
Change Directory的菜單事件處理過程是FileChange,即與文件的移動(dòng)、拷貝、更名共用一個(gè)事件處理過程。詳細(xì)情況請讀者參看(6.4.5.3)中的介紹。
改變當(dāng)前目錄的實(shí)現(xiàn)如下。
procedure TFMForm.ChangeDirectory(Todir: String);
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
DriveTabSet.TabIndex := i;
Exit;
end;
end;
end;
end;
6.4.8 一些問題的處理
6.4.8.1 子窗口的標(biāo)題
Windows的文件管理器是我們設(shè)計(jì)的楷模,在子窗口顯示標(biāo)題上也不例外。我們把當(dāng)前目錄加上文件的類型作為子窗口的標(biāo)題。
過程CreateCaption用于生成子窗口的標(biāo)題。
procedure TFMForm.CreateCaption;
var
Cap: String;
begin
Cap := DirectoryOutline.Directory;
Cap := cap+'\'+FileList.mask;
Caption := Cap;
end;
當(dāng)前目錄或文件顯示類型發(fā)生變化時(shí)改變子窗口的標(biāo)題。如DirectoryOutline的Change事件處理過程和ViewType菜單項(xiàng)的Click事件處理過程就調(diào)用了該過程。
6.4.8.2 狀態(tài)條的顯示
狀態(tài)條用于顯示當(dāng)前目錄和當(dāng)前選中文件。它們的值在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;
procedure TFMForm.FileListChange(Sender: TObject);
begin
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
else
FileManager.FilePanel.Caption := '';
end;
end;
6.4.8.3 版本信息
當(dāng)用戶單擊主窗口的Help|About菜單項(xiàng)時(shí)將彈出一個(gè)About對話框,用于顯示版本信息(如圖6.13)。
這一對話框是用Delphi提供的模板做的。
6.4.8.4 菜單項(xiàng)的變灰與使能
File菜單中定義的文件管理功能只有當(dāng)活動(dòng)焦點(diǎn)在FileList(即有當(dāng)前選中文件)時(shí)才起作用。否則所有菜單項(xiàng)應(yīng)變灰,以免導(dǎo)致系統(tǒng)崩潰。
這一功能在File菜單的Click事件處理過程中實(shí)現(xiàn)。這一點(diǎn)并不很容易被人想到,希望讀者能從中受到啟發(fā)。
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來實(shí)現(xiàn)的。
FileSelected := FileList.ItemIndex >= 0;
6.4.8.5 可重用的文件處理模塊
庫單元fmxutils是一個(gè)代碼庫,提供了若干文件處理模塊。這些模塊除在本程序中使用外,讀者可以在其它應(yīng)用程序中直接調(diào)用,而且不必重新編譯,只要在Uses子句中包含即可。從中我們可以體會(huì)到,Delphi 以庫單元為中心的程序組織方式提供了一種較完善的代碼重用機(jī)制。
6.4.9 小結(jié)
文件管理器是一個(gè)較為綜合的例程,使用到了絕大部分以文件名、文件句柄以及其它參數(shù)(除文件變量)為操作對象的文件管理過程/函數(shù),同時(shí)也提供了一些程序設(shè)計(jì)開發(fā)的思想。我們的介紹是以程序功能模塊來組織的,我建議讀者在學(xué)習(xí)并試圖自己建立這一程序時(shí)采用同樣的方法。(6.4.8)中的內(nèi)容或許是一開始就應(yīng)了解的,但其它完全可以按順序逐步地?cái)U(kuò)充,最后得到一個(gè)完整的程序。這一例程在后邊的拖放操作和異常處理等章節(jié)中還要用到。讀者可以以此為基礎(chǔ)進(jìn)一步完善它,使它真正成為一個(gè)完全實(shí)用的程序。
文件管理是在開發(fā)一個(gè)高級(jí)的Windows程序中不可避免的要涉及到的問題。本章介紹的思路和方法將為讀者成為一個(gè)熟練的程序員奠定基礎(chǔ)。
相關(guān)推薦:2010年9月計(jì)算機(jī)等級(jí)考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |