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過程實現了這一功能!
procedure MoveFile(const FileName, DestName: TFileName);
var
Destination: TFileName;
begin
Destination := ExpandFileName(DestName);
if not RenameFile(FileName, Destination) then
begin
if HasAttr(FileName, faReadOnly) then
raise EFCantMove.Create(Format(SFCantMove, [FileName]));
CopyFile(FileName, Destination);
DeleteFile(FileName);
end;
end;
EFCanMove是一個自定義異常類:
type
EFCanMove := Class(EStreamError);
有關自定義異常類請參閱第十二章。
文件刪除、文件更名直接調用Delphi文件管理過程DeleteFile、RenameFile。它們都以文件名為參數。操作執行前應彈出一個對話框進行確認,執行完畢后應調用Update方法更新FileList的顯示! [1] [2] [3] 下一頁
|