後一頁
前一頁
回目錄
回首頁
第十五章 數據存取部件的應用及程式設計(二)

15.3.6 數據集部件的事件 

    數據集部件TTable或TQuery具有很多的事件。為這些事件編寫相應的程式代碼可以進行有效性驗證、計算可計算欄位的值、確認對資料庫表的多種操作等等。這些事件及其描述如表15.4所示。 

表15.4 數據集部件常用的事件

───────────────────────────────────

事 件 描 述

———————————————————————————————————

BeforeOpen,Afteropen 在數據集部件被打開之前/之後被觸發

———————————————————————————————————

BeforeClose,Afterclose 在數據集部件被關閉之前/之後被觸發

———————————————————————————————————

BeforeInsert,AfterInsert 在數據集部件進入插入狀態之前/之後被觸發

———————————————————————————————————

BeforeEdit,AfterEdit 在數據集部件被編輯之前/之後被觸發

———————————————————————————————————

BeforePost,AfterPost 在數據集部件投寄被修改的記錄之前/之後被觸發

———————————————————————————————————

BeforeCancel,AfterCancel 在數據集部件取消前一步操作之前/之後被觸發

———————————————————————————————————

BeforeDelete,AfterDelete 在數據集部件解除目前記錄之前/之後被觸發

———————————————————————————————————

OnNewRecord 當建立一條新記錄時被觸發

———————————————————————————————————

OnCalcFields 當為表中的計算欄位計算欄位值時被觸發

─────────────────────────────────── 

15.4 TTable部件及應用 

在前一節�塈畯怳雯苳F數據集部件TTable 和TQuery 的共同的一些屬性和方法。TTable部件是Delphi資料庫程式設計中要經常使用的最重要的部件之一,它是資料庫應用程式存取資料庫時必須使用的數據集部件之一,在這一節�堙A我們重點介紹TTable部件特有的屬性和方法,TTable部件所有的屬性、方法和事件都可以在連線輔助敘述中查到。 

15.4.1 TTabel部件主要的屬性 

DatabaseName屬性和TableName屬性:

DatabaseName屬性是敘述資料庫應用程式所操作的資料庫的名字,它可以是由BDE定義的資料庫的別名、顯式敘述的資料庫文件所在的磁碟路徑或者由TDatabase部件定義的一個資料庫名。DatabaseName屬性常常是一個由BDE定義的資料庫的別名。使用由BDE定義的資料庫的別名代替資料庫實際所在的路徑和名字,好處是當實際的資料庫存放的位置發生變化時,只需利用BDE簡單地設定一下該資料庫的別名,而資料庫應用程式無需修改。有關BDE的使用請參看BDE的設定應用。TabelName屬性用以敘述目前TTable部件所連接的實際的資料庫表。這兩個屬性一般都在設計階段指定,當然在程式執行過程中也可以設定,但是要修改這兩個屬性時, 必須要在TTabel的Active屬性為False時進行,當TTable的Active屬性為True時,這兩個屬性是不能被修改和設定的。

TableType屬性:

該屬性敘述與TTable部件相連接的資料庫表的型式。當TableType屬性設定成Default時,該屬性所敘述的資料庫表的型式由資料庫文件的檔案附加名決定。

● 若資料庫文件的檔案附加名為.DB或沒有檔案附加名,表的型式是Paradox表

● 若資料庫文件的檔案附加名為.DBF時,表的型式是dBASE表

● 若資料庫文件的檔案附加名為.TXT時,表的型式是ASCII表 

如果TableType屬性不設定為Default,那麼與TTable 部件相連的資料庫表的型式由TableType中的設定的值決定,不用考慮資料庫文件的檔案附加名。

KeyExclusive屬性:

該屬性的一個作用是敘述在資料庫表中找到記錄時,將記錄移到與找到值相匹配的記錄處還是將記錄指標移到與找到值相匹配的記錄後面一條記錄處。 該屬性是布爾型變數,當它的值為False時(缺省情況下為False), 將記錄指標移到相匹配的記錄處,為True時,將記錄指標移到相匹配記錄的後面一條記錄處。該屬性另一個作用是在表中指定檢索範圍時,用來敘述是否包括滿足過濾條件的邊界記錄。當KeyExclusive的值為False時,檢索範圍包括邊界記錄,否則不包括邊界記錄,有關詳細的操作請參看“限定表中記錄的檢索範圍”。

IndexFields屬性和IndexFieldsCount屬性:

IndexFields的屬性值是資料庫表中欄位名清單,它包含與TTable部件相連的資料庫表中的全部索引字希。IndexFieldsCount屬性敘述表中索引欄位的個數。這兩個屬性值都是唯讀的,只有在程式執行過程中可用。

IndexName屬性和IndexFieldNames屬性:

IndexName屬性中存放著在建立資料庫表時為資料庫表定義的所有輔助索引名,它是一個輔助索引名清單,是唯讀屬性。IndexFieldNames屬性指定用於資料庫表索引排序的欄位名,多個欄位名之間用分號隔開。例如對Customer.DB表中的用戶記錄按郵政編碼ZipCode和用戶號碼CustNo排序時可以設定IndexFieldNames的值為:

ZipCode ; CustNo

在IndexFieldNames屬性中指定的欄位必須存在於相應的資料庫表中,否則會導致錯誤。IndexName和IndexFieldName是互斥的,每次只能指定其中一個屬性的值,不能同時為兩個屬性都指定屬性值。

Exclusive屬性:

該屬性是一個布爾型屬性,它標明是否以共享方式打開資料庫表,如果Exclusive的值為True,當打開一個資料庫表時,其他用戶就不能存取該表了,若Exclusive的值為False,將以共享方式打開一個資料庫表。 顯然不能將其他用戶正在存取的表以互斥方式打開(設定Exclusive的值為True)。對於SQL資料庫伺服器上的資料庫表,當以互斥方式被一個用戶打開時,其他用戶可以讀取該表中的數據,但不能修改表中的數據,當然有些資料庫伺服器不支援這種方式,這要具體參看有關的資料庫伺服器的文檔。

ReadOnly屬性和CanModify屬性:

這兩個屬性都是布爾型屬性,ReadOnly屬性決定用戶是否能夠對表中的數據進行讀寫。ReadOnly為True 時,用戶只能讀取表中的數據,ReadOnly為False時,用戶可以讀寫表中的數據(假設資料庫已授權用戶能夠讀寫其中的資料庫表)。CanModify屬性是一個唯讀屬性,用戶不能夠修改其屬性值,它反映了用戶對資料庫表擁有的實際特權,當ReadOnly為True時CanModify將自動地被置為False,當ReadOnly為False時,如果資料庫允許用戶對表進行讀寫時,CanModify為True,否則CanModify為False。當CanModify為False時,資料庫表是唯讀的,但不能將其置成編輯狀態或插入狀態;當CanModify屬性為True時,雖然資料庫表對應的數據集部件可以置成編輯和插入狀態,但是這並不意味著用戶能夠插入和修改表中的數據,因為這還要受到其他因素的限制,如用戶對SQL資料庫伺服器的存取權限等的限制。

TTable部件還有其他一些屬性請參看連線輔助敘述

 

15.4.2 TTable部件的方法及應用

 

15.4.2.1 設定資料庫表的使用範圍

 

在我們實際應用中的資料庫表中常常存放著大量的數據資訊,其中包含著很多的記錄,而我們的應用程式可能只需對其中一部分記錄進行操作,因此,為應用程式指定一個使用範圍就顯得特別重要了,為方便有效地指定資料庫表的使用範圍Delphi為TTable部件提供了下列方法供用戶使用:

● SetRangeStart和EditRangeStart方法

● SetRangeEnd和EditRangeEnd方法

● SetRange([Start Values],[End Values])方法

● ApplyRange方法

● CancelRange方法

 

1. SetRangeStart方法

用於指定檢索範圍的起始記錄,呼叫SetRangeStart方法之後,可以為起始記錄的一個或多個欄位指定相應的欄位值。SetRangeEnd方法用於指定檢索範圍的結束記錄,呼叫SetRangeEnd方法之後,可以為結束記錄的一個或多個欄位指定相應的欄位值。

 

2. SetRange方法

SetRange方法包含了SetRangeStart和SetRangeEnd方法的功能,它可以同時指定檢索範圍的起始和結束記錄,起始記錄和結束記錄的欄位值以數群群組形式送給SetRange,其基本形式是:

SetRange([起始值],[結束值])

 

3. ApplyRange方法

根據SetRangeStart,SetRangeEnd或SetRange方法敘述的檢索範圍的起始和結束記錄,具體設定一個檢索範圍,呼叫ApplyRange方法之後, 應用程式只能對檢索範圍內的記錄進行有關的操作。

 

4. CancelRange方法

CancelRange方法的作用與ApplyRange方法的作用是相反的,這是取消為表設定的檢索範圍,呼叫CancelRange方法之後應用程式可以對表中全部記錄進行有關的操作。

在這�堶n注意的是:如果我們使用的是paradox表或dBASE表,在呼叫SetRangeStart,SetRangeEnd以及SetRange方法時,只能為表中的索引欄位或定義的索引指定相應的欄位值,以設定檢索範圍。如果使用SQL資料庫伺服器中的資料庫表,可以為IndexFieldNames屬性中指定的欄位指定相應的欄位值。

例如:假設Table1與Customer.DB表相連,Customer.DB中一個索引欄位是CustNo,同時應用窗體中有兩個編輯框StartVal和EndVal用於輸入起始、結束記錄的欄位CustNo的值,下面的程式代碼便可以為我們設定一個檢索範圍:

 

Tabel1.SetRangeStart; {指定檢索範圍的起始記錄}

Tabel1CustNo.AsString:= StartVal.Text {為起始記錄的CustNo欄位指定欄位值}

Tabel1.SetRangeEnd; {指定檢索範圍的結束記錄}

if EndVal.Text <> ' ' then

Tabel1CustNo.AsString := EndVal.Text; {為結束記錄的CustNo 欄位指定欄位值}

Tabel1.ApplyRange; {根據檢索範圍的起始、結束記錄設定檢索範圍}

 

注意上面的程式代碼,在為結束記錄的CustNo欄位指定欄位值時, 首先檢查EndVal的值是否為空,如果EndVal的值為空,那麼設定的檢索範圍沒有包含一條記錄, 因為沒有任何記錄的欄位值小於NIL;如果StartVal的值為空,那麼檢索範圍將從表中的第一條記錄開始,因為表中任何記錄的欄位值都大於空(NIL)。

上述代碼可以用SetRange方法改寫成:

 

If EndVal.Text <>' ' then

Tabel1.SetRane([StartVal.Text].[EndVal.Text]);

Table1.ApplyRange;

 

EditRangeStart和EditRangeEnd方法的使用完全類似於SetRangeStart和SetRangeEnd方法,只是調這兩個方法是設定一個可編輯的範圍。

又如:假設一個表中的一個索引包含兩個欄位LastName和FirstName,我們為索引中的一個欄位或多個欄位指定相應的欄位值,設定資料庫表的使用範圍。

 

Table1.SetRangeStart;

Table1.FieldByName('LastName').Asstring := 'Smith';

Table1.SetRangeEnd;

Tabel1.ApplyRange;

 

上述代碼設定的範圍包括LastName欄位的值大於或等於Smith的所有記錄。而下面的代碼設定的範圍則包括LastName欄位的值大於或等於Smith且FirstName欄位的值大於或等於'J'的記錄。

 

Table1.SetRangeStart;

Table1.FieldByName('LastName').Asstring := 'Smith';

Table1.FieldByName('FirstName').Asstring := 'J';

Table1.SetRangeEnd;

Tabel1.ApplyRange;

 

15.4.2.2 找到資料庫表中的記錄

 

如果想找到資料庫表中的記錄,必須想指定找到記錄的一些欄位的欄位值,然後在表中進行檢索,檢索出與找到值相匹配的記錄來。如果我們是在Paradox或dBASE資料庫中的表中找到記錄,那麼找到值所對應的欄位必須是表中的關鍵欄位或輔助索引欄位。如果找到SQL資料庫伺服器中的表,那麼找到值必須是表的IndexFieldNames屬性中指定的欄位。

Delphi提供了兩種方式在資料庫表中找到記錄:Goto方式和Find方式。這兩種方式十分相似,它們的主要區別在於為找到指定找到值的方法不一樣。

使用Goto方式進行數據找到使用的方法有SetKey方法、GotoKey方法和GotoNearest方法。其實際步驟如下:

 

ヾ確保要找到的欄位是關鍵欄位或輔助索引欄位。

ゝ呼叫SetKey方法把與表對應的TTable部件置成找到狀態。

ゞ把找到值賦給相應的欄位。

々呼叫GotoKey方法,並測試它的返回值檢驗找到是否成功。

 

假設Table1對應的表中第一個欄位是關鍵欄位,Edit1是應用窗體中的一個編輯框,用戶可以通過Edit1輸入找到值。下面的代碼將通過Goto方式進行找到。

 

Table1.SetKey; {將Table1置成找到狀態}

Table1.Field[0].AsString := Edit1.Text; {指定找到值}

Table1.GotoKey; {進行找到}

 

上面最後一行代碼是根據用戶指定的找到值,在表中執行找到。找到的結果有兩種,也許成功也許失敗,這是由呼叫GotoKey方法之後返回的布爾值來決定,如果返回True,那麼找到成功,並且記錄指標會指向與找到值匹配的記錄,如果返回Fale,那麼找到失敗,記錄指標的位置不發生變化。下面的代碼可以測試呼叫GotoKey方法之後的返回值,告知用戶找到是否成功。

 

Table1.SetKey;

Table1.Field[0].AsString:= 'Smith';

If not Table1.GotoKey then

ShowMessage('記錄沒找到')

 

在這一段代碼中,如果在表中沒有找到第一個欄位值為Smith的記錄,該應用程式會彈出一個對話方塊告知用戶“記錄沒有找到”。

如果在表中存在多個關鍵欄位或輔助索引中包含多個欄位時,你在進行找到時,只想為第一個欄位指定找到值,那麼必須要設定TTable部件的KeyFieldCount的屬性值為1。如果想為多個欄位指定找到值,只能為相鄰的欄位指定找到值,例如輔助索引中共有三個欄位,那麼我們只能為第一個欄位、第一和第二個欄位、第一和第二以及第三個欄位指定找到值,而不能為第一和第三個欄位指定找到值。

GotoNearest方法的使用與GotoKey方法完全一樣,只是它用於不精確找到,它不要求找到結果與找到值精確匹配,當表中有與找到值精確匹配的記錄時,它將記錄指標移到該記錄處,當表中沒有與找到值精確匹配的記錄時,它會找到出與找到值最接近的記錄,並將記錄指標移到該記錄處。

下面是應用GotoNearest方法的一段代碼:

 

Table1.SetKey;

Table1.Fields[0].AsString:= 'Sm';

Table1.GotoNearest;

 

執行上述代碼後,若表中存在第一個欄位值等於Sm的記錄時,記錄指標將移到該記錄處,若表中不存在第一個欄位值等於Sm的記錄,而存在第一個欄位值等於Smith的記錄,那麼記錄指標會移到該記錄處。

如果我們不是以資料庫表中的關鍵欄位作為找到欄位,我們也可以為TTable部件的IndexFieldName屬性中的欄位或IndexName屬性中的欄位指定找到值進行數據找到。例如,假設Customer表中有一個名叫CityIndex的輔助索引,我們為CityIndex中的欄位指定找到值進行找到時,首先設定TTable部件的IndexName屬性為CityIndex,然後再進行找到,下面是具體的程式代碼:

 

Table1.IndexName := 'CityIndex';

Table1.Open;

Table1.SetKey;

Table1.FieldByName{'City').AsString := Edit1.Text;

Table1.GotoKey;

 

使用Find方式:使用Find方式在資料庫中進行數據找到的方法有:FindNearest方法和FindKey方法。

FindKey方法和FindNearest方法為數據找到提供了一個簡單的方法,它們將SetKey、指定找到值、執行找到三個步驟融合在一步�塈髡芋A它們在指定找到值時,是把各欄位的找到值群群組成一個數群群組傳給FindKey或FindNearest。下面是使FindKey方法的一個例子。

假設Tabel1對應的表中的第一個欄位是關鍵欄位。

 

Table.FindKey([Edit1.Text]);

 

如果用GotoKey方法完成這一功能則需要編寫下面代碼:

 

Table1.SetKey;

Table1.Fields[0].AsStrine := Edit.Text;

Table1.GotoKey;

 

FindKey方法和FindNearest方法的區別與GotoKey和GotoNearest方法的區別是一樣的。

 

15.4.2.3 建立主要——明細資料庫應用

 

TTable部件中MasterSource屬性和MasterFields屬性是用於定義兩個資料庫表的一對多的關係。MasterSource屬性指定主表對應的TDataSource部件,MasterFields屬性指定主表和明細表之間建立聯繫的欄位,主表和明細表之間建立一對多關係時,可能不只是基於一個欄位,可能有多個欄位。如果有多個欄位,那麼在敘述MasterFields屬性時,多個欄位之間要用分號隔開。如Table1.MasterFields := 'OrderNo;CustNo'。在設計階段可以使用欄位連接設計器(Field Link Designer)為兩上表建立一對多的關係,在Object Inspector 中連續按兩下TTable部件的MasterFields便可以打開Field Link Designer,進行一對多關係的建立。 如建立Customer.DB表和Order.DB表之間的一對多關係時,使用Field Link Designer 如圖15.5所示。

 

 

 

圖15.5 使用Field Link Designer建立一對多關係

 

Field Link Designer提供了一種可視化的方法來建立主要——明細表之間的一對多關係。圖中Available Indexes群群組合框中存放著明細表中的關鍵欄位和索引欄位,可以選擇索引欄位進行連接。在主表中選擇一個用於連接的關鍵欄位,然後將其與明細表中相應的關鍵欄位連接,按一下Add按鈕,主要——明細表的連接欄位將顯示在Joined Fields列示方塊中,如:

CustNo->CustNo 

15.5 TDataSource部件及其應用

 

TDataSource部件是開發資料庫應用程式中用到的非常重要的部件,它是連接數據集部件TTable或TQuery和數據瀏覽部件的橋樑。TDataSource部件本身十分簡單,它所擁有的屬性、事件和方法都比較少,在使用該部件時無需作太多的工作,它主要是為數據瀏覽部件服務的,如果在應用程式中沒有使用數據瀏覽部件,我們也沒有必要為應用程式設定TDataSource部件。

 

15.5.1 TDataSource部件的屬性

 

TDataSource部件除了其他部件都擁有的Name屬性和Tag屬性之外,主要有下面幾個屬性:

DataSet屬性:該屬性敘述TDataSource部件從中獲取數據的數據集的名字,它可以是TTable部件的名字,也可以是TQuery部件的名字,甚至還可以指定其他窗體內的數據集作為該屬性的值,如在下面的程式中我們指定窗體Form2中的table1作為窗體Form1中的DataSource1的DataSet屬性值:

 

TForm1.Formcreate(Sender : Tobject);

Begin

DataSource1.DataSet := Form2.Table1;

end;

 

Enable屬性:Enable屬性可以暫時性地切斷TDataSource部件和與之相連的數據集部件的連接。這是一個布爾型變數。當它的值為False時,TDataSource部件和數據集部件的連接被切斷,且所有與TDataSource部件相連的數據瀏覽部件中將變為一片空白,不顯示任何數據資訊。當Enabled的值變為True時,TDataSource部件和數據集部件的連接恢復,且與TDataSource部件相連的數據瀏覽部件恢復顯示數據。不過要實現上述這些功能,一般不使用TDataSource部件的Enabled屬性,而是呼叫數據集部件的DisableControls方法和EnableControls 方法,因為呼叫這兩個方法可以方便地控制與數據集部件相連的所有TDataSource部件以及與TDataSource部件相連的數據瀏覽部件。

AutoEdit屬性:這是一個布爾型變數,它用於敘述是否將與TDataSource部件相連的數據集置於編輯狀態。當AutoEdit的值為True時,應用程式執行時,與TDataSource相連的數據集部件自動地被設定成編輯狀態,當用戶在與TDataSource部件相連的數據瀏覽部件中輸入新的值時,數據集部件中的記錄也隨之改變。如果AutoEdit的值為False,用戶想通過數據瀏覽部件或程式修改數據集中的記錄,必須要呼叫數據集部件的Edit方法,將其置為編輯狀態之後才能夠進行。

 

15.5.2 TDataSource部件的事件

 

TDataSource部件具有三個事件:

● OnDataChange事件

● OnStateChange

● OnUpdataData

 

OnDataChange事件:當與TDataSource相連的數據集中的記錄指標的位置發生改變時,該事件就被觸發,也就是說當程式呼叫數據集部件的Next、Previous、Insert、Append等方法導致記錄指標的位置發生改變時,便會觸發該事件。該事件一般用於保持應用中多個部件之間的同步。

OnUpdataData事件:當數據集部件中目前記錄將要被修改時,觸發該事件。例如在程式呼叫post方法之後但在修改後的數據記錄真正被寫回磁碟中的資料庫文件之前觸發該事件,在應用中使用非數據瀏覽部件時要它與數據集保持同步時常使用該事件進行相關的處理。

OnStateChange事件:當與TDataSource部件相連的數據集部件的狀態發生改變時, 便觸發該事件。因為數據集部件的State屬性標明了數據集部件目前所處的狀態,當數據集的狀態發生變化時,使用該事件進行有關的處理是很有用的,在一個具體的應用中, 數據集部件的狀態常常是頻繁地變化的,為了跟蹤數據集部件的狀態變化, 可以用下面例子中的程式代碼將數據集部件目前的狀態顯示在一個標籤上:

 

TForm1.DataSource1OnStateChange(Sender : Tobject);

var

S : String;

begin

Case Table1,State of

dsInactive : S := 'Inactive';

dsBrowse : S := 'Browse';

dsEdit : S := 'Edit';

dsInsert : S := 'SetKey';

dsSetKey : S := 'SetKey';

end;

Label1.Caption := S;

end;

 

類似地我們也可以通過偵測數據集部件的狀態來控制有關的按鈕和選擇表項是否有效。 例如:在一個應用窗體中有一個InsertBtn按鈕,用於控制向數據集部件table1對應的資料庫表中插入記錄;還有一個CancelBtn按鈕用於控制是否取消用戶對目前記錄的修改或插入新記錄。下面的程式代碼根據Table1的狀態來控制這兩個按鈕的功能(是否有效,在窗體是否變灰暗)。

 

Form1.DataSource1OnStateChange(Sender : Tobject);

begin

InsertBtn.Enabled := (Table1.State = dsBrowse);

CancelBtn.Enabled := Table1.State in [dsInsert,dsEdit,dsSetKey]

end;

 

上面的代碼中,當Table1處於瀏覽狀態(Browse狀態時), 用戶是不能夠向資料庫表中插入新記錄的,此時InsertBtn按鈕將變灰暗即無效。當Table1不處於Browse狀態時,InsertBtn按鈕有效,用戶是可以向表中插入新記錄。同理,只有當Table1處於特入狀態(Insert狀態)或編輯狀態(Edit狀態)或找到狀態(SetKey狀態)時,CancelBtn按鈕才有效,也即用戶可以取消目前插入的記錄、修改目前的記錄以及找到到的結果等。

 

15.6 欄位部件和欄位編輯器的使用

 

欄位部件有時又稱欄位物件它對應著資料庫表中的列即欄位,欄位物件是不可見的部件,在Delphi中有兩種方式建立欄位部件:

ヾ在應用程式執行過程中,隨著數據集部件被激活,對應於資料庫表中每一列的欄位部件便動態地被建立。

ゝ在設計過程中,程式設計人員利用欄位編輯器(Fields Editor)可以建立永久性的欄位部件,即使欄位物件對應的資料庫表的結構發生了變化時,這些欄位部件也不會發生變化。

既然欄位部件是對應於資料庫表中的各個欄位的,而資料庫表中的欄位有多種數據型式,所以欄位部件相應也有多種型式,欄位部件的型式與資料庫表中的欄位的數據型式的對應關係如表15.5所示。

 

表15.5 欄位部件的型式

────────────────────────────

欄位部件的型式 對應的數據型式

————————————————————————————

TStringField 字元串型式的欄位

TSmallIntField 短整數型式的欄位 -32768-32767

TIntegerField 整數型式的欄位

TWordField 正整數型式的欄位0-65535

TBooleanField 布爾型欄位

TFloatField 浮點數型式的欄位

TCurrenCyField 貨幣型欄位

TDataField 日期型

TTimeField 時間型

TBCDField 小數位數固定的浮點數

TDataTimeField 日期時間型欄位

─────────────────────────── 

我們在本書中只介紹一些常見型式的欄位部件的使用,其他型式欄位部件的使用可以參看連線輔助敘述文件。

 


後一頁
前一頁
回目錄
回首頁