(這麼長!看得我眼都花了.好在找到了我所關心的核心代碼,其他的?別管了吧,我這個懶惰的人.)差的是什麼呢?很明顯,我們希望把這個時候的RecordString開放出去,經過處理之後再回來進行導入的操作.所以,這裡差的只是一個事件處理過程,在這個過程中,我們需要通過Delphi把RecordString的值傳出去讓用戶處理。
既然沒有提供這個接口,那就自己動手添加了。由於需要傳參數,這個事件不能用標准的TNotifyEvent來定義,而需要重新聲明。
新的事件聲明和事件屬性如下:
type
...
TPgCSVRegulateStrEvent = procedure (Sender : TObject; var ARecordString: string) of object;
...
TPgCSV = class(TComponent)
Published
property RegulateString : TPgCSVRegulateStrEvent read FRegulateString write FRegulateString;
//寫完後別忘了按一下ctrl+shift+c
...
End;
好了,現在可以在我剛才注釋的地方寫事件調用方法的程序了.
...
while (not Eof(FFile)) and (not FStop) do
begin
//read from CSV
Readln(FFile,RecordString);
//xm4014's modification
if Assigned(FRegulateString) then
FRegulateString(self,RecordString);
//add new record
try
FDataset.Append;
...
重新編譯包文件通過後,你就會在TPgCSV控件的事件頁面中發現RegulateString這個事件,雙擊它就可以添加你的處理代碼了。這樣一來,無論文本數據中有什麼樣怪異的字符或格式,我們都通過這個事件處理預先過濾一編,讓控件放心的處理導入的操作。簡單吧(也太簡單了點,居然還寫了這麼長!汗)
但是,這樣就行了嗎?
----問題二及解決方案
每一條導入表中的紀錄除了ISO文件中的內容外,還需要有書的類型,期號,以及ID號,而TPgCSV在插入新紀錄時只處理了同文本文件中的數據相關的字段,因此,這些字段的內容需要我們自己來加入。不用說,很自然的就會想到Table中的AfterInsert事件.但問題是,我的Table在DataModule單元中,我必須傳參數到AfterInsert事件中,麻煩!同時,這樣的處理會帶來維護上的混亂,一個單元裡面發生的事件應該盡量由這個單元裡面的函數或過程來處理。於是,我又想到了在當前單元中寫一個處理過程,然後在程序運行時把這個過程指派給Table的AfterInsert事件,導入結束後再禁止掉。可行,但還是麻煩!既然大多數情況下都會遇到這樣的問題,那何不一了百了,把這個事件封裝起來呢.
同問題一一樣,這裡我們還是需要一個事件處理過程AfterInsert.這一次應該加在哪兒呢?大家肯定一眼就看出來了:
procedure TPgCSV.CSVToDataSet;
begin
…
FDataset.DisableControls;
while (not Eof(FFile)) and (not FStop) do
begin
//read from CSV
Readln(FFile,RecordString);
//xm4014's modification
if Assigned(FRegulateString) then
FRegulateString(self,RecordString);
//add new record
try
FDataset.Append;
//應該加在這兒!
//xm4014's modification
if Assigned(FAfterInsert) then
AfterInsert(self,FDataset);
…
for i:=1 to CountMapItems do
…
end;
同樣,這裡需要定義新的事件聲明和事件屬性,因為需要將FDataSet的參數傳遞出去,聲明代碼可參看Delphi控件的拿來主義(二)(http://www.csdn.Net/develop/read_article.ASP?id=11855).
重新編譯控件,就可在AfterInsert事件中添加代碼對書的類型,期號,以及ID號進行賦值了.
----問題三及解決方案
涉及到數據庫的問題現在都已經解決了.但是還有一個顯示問題.程序要求用ProgressBar顯示導入進度.為了設置ProgressBar.Max的值,我需要在導入之前知道ISO文件中一共有多少條紀錄,即一個類似於RecordCount的屬性.但是TPgCSV中沒有這樣的一個屬性.
那麼我們就來添加一個這樣的屬性
//xm4014's modification
property CSVRecordCount : integer read FCSVRecordCount write FCSVRecordCount default 0;
怎麼樣給它賦值呢? 很簡單,可以用ReadLn(F)對ISO文件進行掃描,然後將掃描的次數累加。
關鍵是在哪兒進行這個處理.很顯然,對於同一個文件,這樣的工作只需要做一次就可以了。既然對於不同的文件才需要重新統計,那麼我們可以在每次設置文件名屬性的時候,對文本文件進行掃描。
好,找到TPgCSV的文件名屬性
property CSVFile : string read FCSVFile write FCSVFile;
做一下小小的修改
新的屬性聲明
property CSVFile : string read FCSVFile write SetCSVFile;
按Ctrl+shift+c編寫SetCSVFile的方法代碼如下
procedure TPgCSV.SetFCSVFile(const Value: string);
var
F1:TextFile;
iCount:integer;
begin
if FCSVFile<>Value then
begin
FCSVFile := Value;
//文件名一換,就重新掃描,改變FCSVRecordCount的值
if FileExists(Value) then
begin
AssignFile(F1, Value);
Reset(F1);
iCount:=0;
while not Eof(F1) do
begin
ReadLn(F1);
Inc(iCount);
end;
FCSVRecordCount:=iCount;
end;
end;
end;
編譯之後我們就可以在導入操作進行之前放心的調用CSVRecordCount屬性獲取紀錄個數值了:
ProgressBar1.Min :=0;
ProgressBar1.Max:=PgCSV1.CSVRecordCount;
以上程序在Delphi 6.0/Win98下調試通過
寫到這裡基本上算是大功告成了.其實前前後後做的修改掰著指頭都可以數出來.可就是這麼點小小的升級,讓我真正覺得用起來更加得心應手,我想,下次我再用的時候,會越發體會到它的價值.而且經過這麼一番分析修改,我也長進不少啊,比半瓢多了幾滴,呵呵!
需要指出的是,TPgCSV是一個簡單的控件,它既沒有很復雜的關系,也不涉及到對VCL核心內容的調用,所以在修改的時候是不用有太多的顧慮的.一旦源碼中涉及到很復雜的層次關系時,就需要對你添加或修改的每一行代碼深思熟慮了,不然,可能會牽一發而動全身,最後想回頭都難了.因此,我所說的拿來用的原則實際上還是依托於控件本身的功能,而沒有實質內容上的變動。要達到隨心所欲的境界,各位(我也在內)還要繼續努力啊!