在這一章裡我們主要介紹Delphi的數據訪問部件的層次結構、多部件之間的關系、部件的屬性、方法、事件以及各部件的應用。這些部件包括:
● TSession部件
● 數據集部件(TTable和TQuery)
● TDatasource部件
● 字段對象TField
● 字段編輯器的使用
● TReport部件和TBatchMove部件
我們對這些部件的屬性、方法和事件進行一般性的描述,讀者在實際使用Delphi開發應用程序時,還可以通過聯機幫助獲得有關部件更詳細的信息。
15.1 Delphi數據訪問部件的層次結構
Delphi提供了強大的開發數據庫應用程序的能力,它給用戶提供了大量的數據訪問部件。以方便程序設計人員開發數據庫應用程序。這些部件中,有些部件繼承了另一些部件的屬性、方法和事件,也就是說多部件之間存在著繼承和被繼承的關系,各部件的這種關聯便構成了一個層次結構
圖15.1 Delphi數據訪問部件的層次結構
TSession是全局性的部件,在應用程序運行時,它自動地建立,在設計階段和運行過程中它是一個不可見的部件。
TDatabase部件是為開發客戶/服務器數據庫應用程序時,設置登錄的數據庫的有關參數的,它在數據訪問部件頁上。
TDataset部件是不可見的,TTable和TQuery部件是由它派生而來的,這兩個部件一般被稱為數據集部件,它們在數據訪問部件頁上。
TDatasource部件是連接數據集部件和數據浏覽部件的橋梁,它在數據訪問部件頁上。
TFields部件對應於數據庫表中的實際字段,它既可以在應用程序的運行過程中動態地生成也可以在程序設計階段用字段編輯器創建。它是不可見的部件,在程序中我們可以通過TField部件來訪問數據庫記錄的各個字段值。
15.2 Tsession部件及其應用
TSession部件一般用得較少,但它對於一些特殊的應用是很有用的,在每一個數據庫應用程序運行時Delphi自動地創建一個TSession部件。程序設計人既不能看見該部件也不能顯示地創建一個TSession 部件,但是我們可以在應用程序中全局性地使用TSession部件的屬性、方法。
15.2.1 TSession部件的重要屬性及作用
TSession部件的許多重要屬性是用於控制數據庫應用程序與數據庫的連接的,在一個應用程序中,可以全局性地設置TSession的有關屬性值,對與之相連接的磁盤上的數據庫進行控制。TSession部件主要有下列屬性:
Database屬性:是TSession中可以進行連接的所有數據庫的數據庫名字列表,這些數據庫的名字常常是實際數據庫的別名,包括數據庫的路徑、用戶名、用戶登錄口令等參數。
DatabaseCount屬性:是TSession中可以進行連接的所有數據庫的數量,它是一個整數。
KeepCounnections屬性:是一個布爾型屬性,用它說明應用程序是否保持與一個非活動數據庫的連接。因為對於一個數據庫,當該數據庫中沒有相應的數據集部件(TTable或TQuery)被打開時,該數據庫將自動地變成非活動的數據庫。缺省情況下,KeePcounnections的值是True,就是說應用程序總是保持著與數據庫的連接,即使數據庫變成了非活動的數據庫時,也是如此。如果將KeepConnections屬性設置成False,那麼當數據庫由活動狀態變成非活動狀態時,應用程序與該數據庫的連接也隨之中斷。
NetFileDir屬性:說明BDE網絡控制文件的路徑名。
PrivateDir屬性:說明存取臨時文件的路徑名。
15.2.2 TSession部件的方法:
TSession部件中的大部分方法是用於向用戶提供與應用程序相連接的數據庫的信息,如數據庫的名字及別名,數據庫中的表名以及數據庫引擎BDE的有關參數等,在設計數據庫應用程序時,想要獲取有關數據庫的信息,調用TSession部件的下列方法,將會大大簡化程序的設計。
GetAliasNames方法:調用該方法,我們可以獲得數據庫引擎BDE中定義的數據庫別名。
GetAliasParams方法:該方法主要用於獲取我們在BDE中定義數據庫別名時所說明的參數值,如BDE所在的目錄路徑以及實際名稱等。
GetDatabaseNames 方法:調用該方法可以幫助我們獲得當前應用程序可以進行連接的所有數據庫的名字,數據庫的名字是用戶使用BDE工具定義的實際數據庫的別名。
GetDriverNames方法:數據庫引擎BDE可以與多種數據庫管理系統相連接,如客戶/服務器數據庫管理系統Oracle、Sybase以及本地數據庫管理系統dBASE,Paradox等,BDE與每一種數據庫管理系統進行連接時,都有相應的驅動程序,而且這些驅動程序都可以選擇地安裝。通過調用GetDriverNames方法。我們可以獲得當前BDE安裝的數據庫驅動程序的名字。
GetDriverParams方法:BDE的數據庫驅動程序中包含著多個參數,如支持的民族語言、DBMS的版本號、文件塊大小等,對於服務器上的DBMS,還有數據庫服務器的名字等等。
GetTableNames方法:因為每一個數據庫都是由多個數據庫表組成的,我們通過說明數據庫名,然後調用GetTableNames方法,便可以獲得該數據庫中全部的數據庫表的名字。
上述這些方法在調用時都需要一個字符串列表作為參數,而且都返回一個字符串列表的值。
TSession部件還有一個叫DropConnections的方法用於控制應用程序與數據庫的連接,當調用DropConnections方法時,應用程序與所有的數據庫的連接將會切斷。
15.2.3 TSession部件應用舉例
例15.1:我們創建一個應用程序,通過調用TSession有關的方法獲取當前應用程序可以進行連接的數據庫的名字以及獲取其中任意一個數據庫中的全部數據庫表的名字。
通過TSession部件獲取數據庫的有關信息
窗體中主要使用了兩個列表框,其中列表框DatabaselistBox用於顯示數據庫的名字,列表框TablelistBox用於顯示數據庫中的表名。程序運行完後數據庫的名字顯示在DatabaselistBox列表框中,當用戶單擊DatabaselistBox列表框中的數據庫名時,該數據庫全部的數據庫表的名字將會顯示在TablelistBox列表框中。有關的程序代碼如下:
程序清單15.1
unit unit31;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, DB, DBTables, Buttons, ComCtrls, Tabnotbk;
type
TQueryForm = class(TForm)
BitBtn1: TBitBtn;
DataSource1: TDataSource;
Table1: TTable;
GroupBox1: TGroupBox;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
ListBox1: TListBox;
ListBox2: TListBox;
ListBox3: TListBox;
TabSheet2: TTabSheet;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure ListBox2Click(Sender: TObject);
end;
var
QueryForm: TQueryForm;
implementation
{$R *.DFM}
uses RSLTFORM;
procedure TQueryForm.FormCreate(Sender: TObject);
begin
Screen.Cursor := crHourglass;
{ Populate the alias list }
with ListBox1 do
begin
Items.Clear;
Session.GetAliasNames(Items);
end;
{ Make sure there are aliases defined }
Screen.Cursor := crDefault;
if ListBox1.Items.Count < 1 then
MessageDlg( 'There are no database aliases currently defined. You ' +
'need at least one alias to use this demonstration.',
mtError, [mbOK], 0 );
end;
procedure TQueryForm.ListBox1Click(Sender: TObject);
var
strValue: string; { Holds the alias selected by the user }
bIsLocal: Boolean; { Indicates whether or not an alias is local }
slParams: TStringList; { Holds the parameters of the selected alias }
iCounter: Integer; { An integer counter variable for loops}
begin
{ Determine the alias name selected by the user }
with ListBox1 do
strValue := Items.Strings[ItemIndex];
{ Get the names of the tables in the alias and put them in the
appropriate list box, making sure the user's choices are reflected
in the list. }
ListBox2.Items.Clear;
Session.GetTableNames(strValue, { alias to enumerate }
'', { pattern to match }
15.3.4 數據集中的數據維護
數據集中的數據維護主要包括數據記錄的修改,插入和刪除。Delphi為數據集部件提供了相應的方法用於其中的數據維護。這些方法如表15.所示。
表15.3 Delphi用於數據維護的方法
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
方 法 名 功 能
──────────────────────────────
Edit 將數據集置為編輯狀態
──────────────────────────────
Append 投寄所有被修改的記錄,將記錄指針移到表中的最後
一條記錄,且將數據集置為插入狀態
──────────────────────────────
Insert 投寄所有被修改的記錄將數據集置為插入狀態
──────────────────────────────
Post 將插入的新記錄和修改的記錄寫回磁盤上的數據庫表,
即投寄,當投寄成功時數據集回到浏覽狀態,若投寄
不成功數據集仍然保持原有狀態
──────────────────────────────
Cancel 取消當前的操作且將數據集置為浏覽狀態
──────────────────────────────
Delete 刪除當前記錄指針所在的記錄且將數據集置為浏覽狀態
──────────────────────────────
AppendRecord 在表的最後插入一條新記錄,記錄的各個字段值作為
AppendRecord的參數傳遞給新記錄
──────────────────────────────
InsertRecord 在當前指針所在記錄的後面插入一條新記錄, 記錄的
各個字段值作為InsertRecord的參數傳遞給新記錄。
──────────────────────────────
SetRecords 修改當前記錄,字段名和相應的字段值作為SetRecords
的參數
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Edt方法:如果應用程序想對數據集中的數據記錄進行修改,我們必須要將數據集設置成編輯狀態。調用數據集部件的Edit方法便可以將數據集置成編輯狀態,當數據集已經處在編輯狀態時,調用Edit方法不會產生作用。當數據集處於編輯狀態時,移動記錄指針或調用post方法都可以將當前記錄的修改寫回到磁盤數據庫表中。在程序中, Edit方法和post方法常常配合在一起使用,用於修改表中的記錄。如:
Table1.Edit;
Tabel1.FieldByName('CustNo').Asstring := '1234';
Table1.st;
在上述這一段程序代碼中,第一行程序是將Table1置成編輯狀態,第二行程序是對當前記錄指針所在的記錄的CustNo字段的值修改成'1234',第二行程序是調用post方法將對當前記錄的修改寫回數據庫表。
Append方法和Insert 方法:這兩個方法都是將數據集部件置成插入狀態,以在表中插入新記錄,Insert方法是在當前指針位置的記錄後面插入一打新記錄,Append方法是在表的尾部插入一打新記錄,不過這要注意,無論用戶是調用Insert方法還是Append方法插入新記錄,增加記錄到一個具有索引的表中時,都是按照索引順序寫入其位置,也就是說對於索引表格Insert方法和Append方法的作用是一樣的,Append僅適用於沒有索引的表。Insert方法和Append方法實際上是將數據集置成插入狀態,並且插入一條空白記錄,要真正插入一條新記錄,我們必須在調用Insert或Append方法之後,還要給新記錄的各個字段賦值,最後調用post方法,將插入的記錄寫回數據庫表。調用這兩種方法插入新記錄的一般步驟如下:
With tabe1 DO
Begin
Insert; {調用Insert方法,插入一條空記錄}
<為記錄的各字段賦值>
Post;
End;
Post方法:數據集中的記錄被修改或插入新記錄時調用post方法將數據集的修改寫回到數據庫表。根據數據集所處的狀態不同,post方法所產生的作用和效果是不一樣的:
● 當數據集處於編輯狀態時,調用post方法,將當前記錄的修改寫回數據庫表
● 當數據集處於插入狀態時,調用post方法,將插入的新記錄寫回數據庫表
● 當數據集處於SetKey狀態時,調用post方法,將數據集置成浏覽狀態(Browse狀態)
post方法的調用既可以顯式地調用,也可以隱含地調用,當數據集處於編輯狀態或插入狀態時,當移動記錄指針時,Delphi會隱含地調用post方法,將將當前記錄的修改寫回數據庫表,在程序調用Insert方法或Append方法時,也會隱含地調用Post方法,將先前的數據集的修改寫回數據庫表。
Delete方法:Delete方法用於刪除表中的記錄,調用Delete方法時,將會刪除表中當前的記錄,並且自動地將記錄指針移到被刪記錄的下一條記錄,同時將數據集置成Browse狀態。
Cancel方法:Cancel方法用於取消當前的操作,當程序還沒有調用Post方法,將對記錄的修改寫回數據庫表時,調用Cancel方法,可以將記錄恢復到沒有修改之前的狀態。並且在調用Cancel方法時,它總是將數據集置成Browse狀態。
AppendRecord方法和InsertRecord方法:這兩個方法分別與Append方法和Insert方法相似。它們都是用於在表中插入一條新記錄,但AppendRecord方法和InsertRecord方法比Append和Insert方法更簡單更方便一些,它們直接在表中插入一條新記錄,新記錄的各個字段值作為AppendRecord或InsertRecord方法的參數傳遞給新記錄並且不需顯式地調用post方法,將插入的新記錄寫回數據庫表。在給插入的新記錄賦字段值時,將由多個字段值組成的數組作為AppendRecord或InsertRecord的參數,在字段值數組中可以為每一個字段提供一個值,或從左邊一列開始依次為任意多個字段賦值。也就是說,用戶可以從數據庫表的最左一列起,把許多列的值同時傳遞給InsertRecord,直到所有的字段被賦值,用戶也可以省略字段序列後面的的一些字段值,InsertRecord會用空值來填充這些字段:用戶也可以對那些明確希望用空填充的字段傳遞保留字NIl。
例如:如果表Country有Name,Captial,Continent,Area和Population字段,並且數據集部件Table1與它相連,下面的代碼便可以在Country表中當前記錄的後面插入一條新記錄。
Table1.InsertRecord (["中國","北京","五洲"]);
在上述代碼中沒有為Area和population字段賦值,InsertRecord會用空值來填這兩個字段。
SetRecords方法:調用該方法可以修改表中當前記錄的多個字段的值,調用該方法之前必須將數據集部件置成編輯狀態,調用該方法之後,還要調用post方法,才能真正將當前記錄的修改寫回數據庫表。調用SetRecord方法時,被修改的字段值必須要與表中實際存在的字段名對應,並且數據類型要相匹配。例如,下面的代碼是修改上面剛剛插入的那條記錄。
Table1.Edit;
Tabel1.SetRecord(, , ,9600000,1200000000);
Tabel1.post;
這一段代碼是修改上面剛剛插入的那條記錄的Area 和Population 字段的值,而對Name,Continent和Captial字段沒有修改。
在數據集部件中,還有一個重要方法Abort方法,該方法是用於取消其他方法的調用的,如在插入記錄、修改記錄和刪除記錄之前,往往需要用戶確認是否真的要執行這種操作,此時調用Abort方法便可取消各種方法的調用,下面的代碼是在用戶刪除一條記之前,讓用戶確認是否真的要執行刪除操作。
Tabel1.BeforeDelete(DataSet:TDataSet);
If MessageDlg('真的要刪除記錄嗎?',
mtConfirmation,mbyesNoCanel,0 <> mryes then
Abort; {取消刪除操作}
關於書簽(BookMark)操作;
書簽操作主要用於在表中快速地定位記錄指針,在應用程序中常常要保存記錄指針所在的位置,在進行其他處理之後,希望能快速地返回到先前指針所在的位置,此時,使用書簽將顯得特別有用。有關書簽操作,Delphi提供了三個方法,它們是:
● GetBookMark
● GotoBookMark
● FreeBokMark
這三個方法一般都是在一起使用,GetBookMark方法返回一個TBookMark類型的變量,該變量包含著指向當前記錄的指針,GotoMark方法用於快速地將記錄指針定位到具有書簽的記錄處。FreeBookmark方法是與GetBookMark方法相反的操作,它釋放書簽標志。下面的程序代碼闡述了書簽操作的一般方法:
BookMark : TBookMark;
<Do something>
BookMark := Table1.GetBookMark; {對當前記錄作書簽標志}
Table1.DisalbeControls; {切斷Table1與數據察覺部件的聯系}
Table.First
While Not EOF Do {對表中全部記錄進行其他處理}
begin
<Do something>
Tabel1.Next;
end;
Tabel1.GotoBookMark(BookMark)
Table1.enableControls; {重新定位記錄指針回到原來的位置}
Tabel1.FreeBookMark(BookMark); {刪除書簽BookMark標志}
15.3.5 數據集部件與數據浏覽部件的連接
數據集部件TTabel和TQuery具有三個方法,DisableControls 方法、EnableControls方法、Refresh方法用於控制數據集部件和與其相連的數據浏覽部件之間的連接,以及控制數據浏覽部件的顯示。在用戶修改和更新以及遍歷數據庫表中的記錄時,調用DisableControls方法具有重要意義,調用DisbaleControls方法以切斷TTable或TQuery部件與數據浏覽部件的連接,使數據浏覽部件暫時失效,否則,在對TTable或TQuery部件的每次修改之後,窗體中所有與它們相連的數據浏覽部件都要更新其顯示內容,這親顯然會減慢處理速度。當遍歷表中的記錄時記錄指針每移動一下,窗體中的數據浏覽部件也隨之更新一下其中的顯示內容,在屏幕上產生閃爍。
EnableControls方法的作用與DisbaleControls方法的作用是相反的,調用EnableControls方法,使TTable或TQuery部件恢復與數據浏覽部件的連接,使暫時失效的數據浏覽部件恢復到正常顯示表中記錄信息的狀態。
Refresh方法用於刷新數據浏覽部件中的顯示。在調用Refresh方法時,必須要確保TTable或TQuery部件是打開的。當數據集中的記錄被修改之後,調用Refresh方法,數據浏覽部件中顯示的信息也隨之改變。
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部件及應用
在前一節裡我們介紹了數據集部件TTable 和TQuery 的共同的一些屬性和方法。TTable部件是Delphi數據庫編程中要經常使用的最重要的部件之一,它是數據庫應用程序訪問數據庫時必須使用的數據集部件之一,在這一節裡,我們重點介紹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方法之後應用程序可以對表中全部記錄進行有關的操作。
在這裡要注意的是:如果我們使用的是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、指定查找值、執行查找三個步驟融合在一步裡完成,它們在指定查找值時,是把各字段的查找值組成一個數組傳給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 日期時間型字段
━━━━━━━━━━━━━━━━━━━━━━━━━━━
我們在本書中只介紹一些常見類型的字段部件的使用,其他類型字段部件的使用可以參看聯機幫助文件。
15.6.1 字段部件
字段部件在應用程序中始終是不可見的部件。在程序運行過程中是如此,在程序設計階段也是如此,但是它在應用中起著非常重要的作用,可以說它是所有數據浏覽部件從數據庫表中顯示、編輯數據的基礎。這是因為字段部件直接對應著數據庫表中的字段,浏覽和修改表中的數據必須要通過字段部件,同時字段部件所擁有的屬性可以用來說明數據庫表中對應的字段的數據類型、當前的字段值、顯示格式、編輯格式等,字段部件的事件如OnValidate可以用來設定輸入字段值時進行有效性檢驗。
數據庫表的每一列在應用程序中都有其對應的一個字段部件,在缺省情況下,當TTable或TQuery的Active屬性被置為False或調用close方法時,與表中各列對應的字段部件也隨即消失,要想為應用程序創建永久性的字段部件,我們必須要在程序設計階段使用字段編輯器(Fields Editor)來創建。使用字段編輯器創建永久性字段的好處是:我們在程序代碼中利用永久性字段部件可以更加有效、方便、可靠地訪問數據庫表中記錄的各字段值,在任何時候我們都可以以同樣的字段順序、固定的字段顯示表中的記錄,即使數據庫表的結構已發生了變化。當然如果在數據庫表中與字段部件對應的字段已經不存在時,應用程序就不能正常地執行下去了,Delphi會彈出一個錯誤信息框,告訴用戶表中的字段已經不存在了。
15.6.1.1 字段部件的屬性及應用
字段部件具有很多的屬性,通過設置字段部件有關的屬性,可以控制字段對象在數據浏覽部件中的顯示方式、字段值能否被修改等。特別是對於用字段編輯器創建的永久性的字段部件,我們在程序設計階段便可以在Object Inspector中方便地選取字段部件, 進行有關屬性的設置。
字段部件的主要屬性如表15.6所示,該表中列出的屬性只是字段部件的部分屬性,它主要用來控制字段對象的顯示方式。
表15.6 字段部件的主要屬性
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
屬性名 功 能
───────────────────────────────
Alignment 說明字段值在數據浏覽部件中顯示時的對齊方式:
左對齊、右對齊、居中三種方式。
───────────────────────────────
Calculated 說明字段是否是計算字段,屬性值為True時,該
字段是計算字段、字段值可以根據表中其它字段
的值計算得出。
───────────────────────────────
Currency 等於true時,以貨幣格式顯示數值,等於False時,
不以貨幣格式顯示數值型數據。
───────────────────────────────
DisplayFormat 用於說明字段值在數據浏覽部件中的顯示格式
───────────────────────────────
DisplayLabel 字段在網格(TDBGrid部件)中顯示時,為字段指定
顯示標題。
───────────────────────────────
DisplayNidth 字段在網格(TDBGrid部件)中顯示時,為字段指定
顯示寬度,單位是字符數。
───────────────────────────────
EditFormat 說明字段在數據浏覽部件中的編輯輸入格式
───────────────────────────────
EditMask 在進行字段值的編輯輸入時,限定輸入字段值的
過濾條件(即字段值的范圍)。
───────────────────────────────
FieldName 該字段部件對應實際數據庫表中的字段的名字
───────────────────────────────
Index 該字段部件在數據集所有字段部件中的順序號
───────────────────────────────
MaxValue 說明可以為該字段輸入最大的數值
───────────────────────────────
MinValue 說明可以為該字段輸入最小的數值
───────────────────────────────
Name 字段部件的名字
───────────────────────────────
ReadOnly 等於true時,只能讀取該字段的字段值,不能修改;
等於False時,可以對該字段的字段值進行讀寫。
───────────────────────────────
Size 說明字段的大小,單位是字符數
───────────────────────────────
Visible 為True時,該字段可以在TBDBGrid部件中顯示;
為False時,該字段不能在TDBGrid部件中顯示
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
表15.6中的屬性並不是所有類型的字段部件都擁有的,如一個TStringField類型的字段部件是沒有Currency、MaxValue、MinValue和DisplayFormat屬性的,一個TFloatField類型的字段部件是沒有Size屬性的。
對於布爾型屬性,在設計過程中的Object Inspector中雙擊該屬性,該屬性的值將會在True和False之間來回切換,其他屬性需要用戶輸入屬性值或從下拉式列表框中選取屬性值。所有的屬性都可以通過程序代碼進行設置。大多數屬性可以獨立地設置,只有DisplayFormat,EditFormat和EditMask是相互聯系的。在設置它們的屬性值時一定要確保相互協調。
利用EditMask屬性為字段設定編輯模式:
為字段部件設置一定的EditMask屬性值,當編輯輸入該字段的字段值時,用戶只能根據EditMask設定的編輯模式進行編輯或輸入字段值。在為EditMask屬性設置屬性值時可以用手動方式也可以用輸入模式編輯器來完成,當為某字段部件設置EditMask屬性時,雙鼠標雙擊EditMask屬性便可以打開輸入模式編輯器(Input Mask Editor) 。例如在為Customer.DB表的Phone字段設定編輯模式時,首先在Object Inspector中選取與Phone字段對應的Table1Phone字段對象,然後雙擊EditMask屬性,打開輸入模式編輯器。
字段輸入模式編輯器
在字段輸入模式編輯中可以選擇一種輸入模式,而且在TestInput編輯框中輸入字段值進行檢驗。
因為TStringField類型的字段部件沒有DisplayFormat屬性,但是可以把EditMask屬性當DisplayFormat屬性使用。
設定字段的顯示和編輯格式:
Delphi本身為某些類型的字段對象提供了設定其顯示和編輯格式的例程,並且為字段部件的DisplayFormat和EditFormat屬性指定了缺省值,例如對於與浮點型數值字段對應的TFloatField類型的字段部件,而且該字段部件的Currency屬性設置為True 時,字段值1234.56的顯示格式為$1234.56,編輯格式是1234.56。表15.7是Delphi提供了設置字段顯示和編輯格式的例程。
表15.7 字段格式例程
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
例 程 名 運用的字段對象
─────────────────────────────
FormatFloat TFloatField,TCurrencyField
FormatDateTime TDateField,TTimeField,TDateTimeField
FormatInteger TIntegerField,TSmallIntField,TWordField
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
上述這些用於設定日期時間類型、數值型以及貨幣型字段的顯示和編輯格式的例程,都是按國際上通行格式來設定相應類型字段的格式的,用戶可以自己設置字段部件的DisplayFormat和EditFormat屬性,來設定適合自己使用的格式,還可以為有關字段對象的OnGetText和OnSetText事件編寫代碼來設定字段的顯示和編輯格式。
15.6.1.2 字段部件的事件及應用
字段部件常需處理的事件如表15.8所示
表15.8 字段部件的事件
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
事件名 用 途
────────────────────────────
OnChange 當字段部件的字段值發生改變時,觸發該事件
OnGetText 當字段部件獲得字段值時,觸發該事件
OnSetText 當字段部件被設置字段值時,觸發該事件
OnValidata 當字值被修改或插入新的字段值時,對字段值
進行有效性檢驗時,觸發該事件
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
用戶想自己設定字段的顯示和編輯格式時,可以編寫OnGetText事件和OnSetText事件的處理過程,以達到設定字段的顯示和編輯格式。
15.6.1.3 字段部件的類型轉換函數及使用
字段部件具有一些內部函數用於轉換字段值的類型,對於不同的字段類型,這些轉換函數的作用是不一樣的,表15.9概括了不同類型的字段及轉換函數的作用。
表15.9 字段部件的轉換函數
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
字段類型 AsString AsInteger AsFloat AsDatetime AsBoolean
────────────────────────────────────
TStringField 轉換成 轉換成整數 若能轉換 日期 轉換成布型
Stringg型 (若能轉換) 則轉換成 (若能轉換)
────────────────────────────────────
TIntegerField
TSmallField 字符型 整數型 浮點型 不允許 不允許轉換
TWordField
────────────────────────────────────
TFloatField
TCurrencyField 字符串型 捨入成整數 浮點型 不允許 不允許
TBCDField
────────────────────────────────────
TDateField
TDateTimeField 字符串 不允許 浮點數 日期型 不允許
TTimeField
────────────────────────────────────
TBooleanField 轉換成Time 不允許 不允許 不允許 布爾型
或False
────────────────────────────────────
TBytesField
TVarBytesField 字符串 不允許 不允許 不允許 不允許
TBlobField
────────────────────────────────────
TMemoField 二進制 不允許 不允許 不允許 不允許
TGraphilField 字段
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
上述這些轉換函數可以在任何與字段部件有關的表達式中使用,只要是表15.9中允許進行轉換的數據類型,這些轉換函數其實是當做字段部件的屬性來使用的,它們可以出現在賦值語句的兩邊。例如下面的程序代碼是將字段部件TableMyField的字段值轉變成字符串類型的數據,並將它賦給編輯框Edit1的Text屬性:
Edit1.Text := TableMyField.AsString;
而下面的代碼是進行相反的操作,它將編輯框部件Edit1的Text屬性值以字符串的形式賦給字段TableMyField,TableMyField通過AsString接受字符串並將其轉變成自身的數據類型。
TableMyField.AsString :=Edit1.Text;
15.6.1.4 字段部件的訪問
字段部件對應著數據庫表中實際的字段,用戶要讀寫數據庫表中的字段值其實是通過訪問相應的字段部件進行的。在前面的章節中我們介紹過在Delphi的數據庫應用程序中有兩類字段部件:一類是利用字段編輯器創建的永久性字段部件;另一類是隨著數據集部件被激活(被打開)而動態生成的字段部件。對於永久性字段部件的訪問可以直接調用使用字段部件的名字進行。假設我們在設計階段利用字段編輯器創建了對應於Customer.DB表中Company字段的字段部件Table1Company,下面的代碼訪問Company字段的字段值,並將該字段值顯示在編輯框部件Edit1中。
Edit1.Text := Table1Company.Value;
因為company字段是字符串類型的數據,它與Edit1中的數據類型相匹配的,因此可以直接使用字段部件的Value屬性讀取字段值。如果兩個變量的類型不匹配,則要使用表15.9中的轉換函數進行字段值的讀取。例如:要讀取Customer.DB表中的CustNo字段的值並將它顯示在編輯模框Edit1中,假設我們已用字段編輯器(Fields Editor)創建了CustNo相應的字段部件,Table1CustNo,則程序代碼如下:
Edit1.Text := Table1CustNo.AsString;
訪問動態生成的字段部件相對要困難一些,因為動態生成的字段部件是沒有自己的名字的,我們必須利用特殊的手段獲得數據庫表中各字段對應的字段部件,然後對字段進行訪問。一般采用的方法有兩種:
● 使用數據集部件的Fields屬性
● 使用數據集部件的FieldByName方法
1. 使用數據集部件的Fields屬性訪問數據庫表中各字段
數據集部件的Fields屬性是與數據集部件相連的數據庫表中各個字段對應的動態字段部件的名字列表,因此我們可以通過Fields屬性的下標(即索引號)來訪問各字段部件,從而達到訪問數據庫表中的各個字段,索引號從0開始,也就是說數據庫表中第一個字段對應著Fields列表的第一行即0索引,第二個字段對應的Fields的索引號為1,以此類推。下面的例子是訪問Customer.DB表中的第一個字段並在編輯框Edit1中顯示其字段值。假設Table1與數據庫表Customer.DB相連。
Edit1.Text := Table1.Fields[0].AsString;
下面的代碼是將編輯框Edit1中的字符值賦給Customer.DB表中當前記錄的第一個字段,以實現修改Customer.DB表中的字段值。
Table1.Fields[0].AsString := Edit1.Text;
2.使用數據集部件的FieldByName方法訪問字段部件
在數據集部件所擁有的方法中,有一個FieldByName方法,它是專門用於訪問數據集部件中動態生成的字段部件的,調用FieldByName方法時,必須要把數據庫表中的字段名作為參數傳給FieldByName,調用該方法後便可以得到該字段所對應的字段部件,這樣通過字段部件我們便可以讀寫表中相應的字段值了,用這種方法訪問字段部件時,必須要知道數據庫表中各個字段的名字,否則是沒有辦法調用該方法的。還是基於上面的假設。下面是訪問Customer.DB表中的CustNo字段的程序代碼:
在字段編輯器Fields Editor窗體上面的導航按鈕是用來移動TTable或TQuery部件中的記錄指針的,使用導航按鈕可以將記錄指針向前、向後移動,也可以移到第一條記錄處或最後一條記錄處。
字段編輯器中的彈出式菜單
15.6.2.2 增加字段部件
字段編輯器Fields Editor中的Add Fields菜單項用於向數據集部件中增加字段部件的,單擊Add Fields菜單項時便會打開增加字段部件對話框,如圖15.9所示。Available Fields列表框中顯示出數據集部件TTable或TQuery中當前可以用於創建永久字段部件的全部的字段,也就是說Available Fields列表框中顯示字段是數據庫表中實際存在的字段,而且還沒有為這些字段創建相應的永久性的字段部件,在缺省狀態下所有的字段都被選擇用於創建相應的永久性的字段部件,用鼠標單擊其中的字段名可以有選擇地創建其相應的永久性的字段部件,選擇好有關的字段名之後,單擊OK按鈕便可以創建永久性的字段部件。
字段編輯器的增加字段部件對話框
15.6.2.3 刪除字段部件
用字段編輯器Fields Editor為數據集部件創建好的字段部件都會顯示在字段編輯器的Fields列表框中,如果用戶認為其中的一些字段部件不合適或不再需要時,可以單擊這些不需要的字段部件,然後單擊鼠標右鍵彈出一傭彈出式菜單,從彈出式菜單中選擇Delete菜單項,便可刪除相應的字段部件,如果在彈出式菜單中單擊Select All菜單項,然後選擇Delete菜單項,這樣會刪除已創建好的所有的字段部件。某一個字段部件被刪除以後,通過單擊Add Fields菜單項可以重新創建,只是先前為該字段部件設定的一些屬性將不復存在。
15.6.2.4 定義新的字段部件
字段編輯器Fields Editor中的彈出式菜單中New Fields菜單項是用來為數據集部件TTable或TQuery創建用於顯示目的的新的字段部件,我們可以用它來為數據庫表中實際存在的字段創建新的字段部件(如改變字段的數據類型,使它的字段值被顯示時不再需有關的類型轉換),但是我們使用New Fields菜單項創建新的字段部件主要是創建計算字段。計算字段並不與數據庫表中實際存在的字段對應,它的字段值是根據表中其它的字段值計算而來的,具體的計算表達式由用戶為TTable部件或TQuery部件的OnCalCFields事件編寫程序代碼時決定。
定義(創建)計算字段的過程如下:
1.單擊字段編輯器中的New Fields菜單項,定義字段對話框如圖15.11所示。
2.在FieldName編輯框中輸入新字段部件的名字,或者從下拉式列表框中選擇一個已存在的字段部件的名字。
3.在FieldType列表框中為新字段部件選擇一個字段類型。
4.單擊Calculated檢查框,確認定義的新字段部件是計算字段。
5.單擊ok按鈕,創建上述定義的計算字段部件,此時該字段部件的名字會自動地加入到字段編輯中的Fields列表框中。
創建新的計算字段
新的計算字段創建好了之後,它是沒有任何字段值的,我們必須要編寫相應的程序代碼,根據數據庫表中實際存在的字段的字段值為計算字段的寶定義字段值,我們為計算字段所在數據集部件的OnCalcFields事件編寫代碼來為計算字段賦值,其步驟如下:
1.選擇數據集部件TTable或TQuery
2.單擊數據集部件的事件頁
3.雙擊OnCalcFields事件為TTable或TQuery部件編寫事件處理過程
15.7 TReport部件及其應用
在一般的數據庫應用程序中都包含著為最終用戶提供輸出報表的功能,使用Delphi開發數據庫應用程序時,可以使用一個叫TReport的部件來執行報表功能的,報表的具體格式和內容是由Delphi提供的一個專用報表生成工具ReprotSmith創建的,它報表的具體格式和內容生成一個報表文件,然後為TReport部件設置相應的屬性參數,由TReport部件執行報表功能。
我們可以在設計階段雙擊TReport部件,調用ReportSimith工具或者在Delphi程序組內雙擊ReportSmith圖標來調用ReportSmith工具來創建一個報表文件,具體的操作步驟和設計方法請參看ReportSimth工具的使用說明。
我們在使用TReport部件執行報表功能時,要設置TReport部件的一些的一些屬性,這些屬性是:
ReportName屬性:說明報表文件的名字,就是用ReportSmith創建的報表文件。
ReportDir屬性:說明報表文件所在的途徑名。
PreView屬性:這是一個布爾型屬性。若它的值為True,那麼在執行報表功能時,只是在屏幕上顯示報表;若它的值為False,則報表內容將在缺省的打印機打印出來。
AutoUnload屬性:布爾型屬性,它的值為True時,在執行完一個報表功能後,自動地從內存中卸出ReportSmith工具;它的值為False時,在運行完一個報表功能後,不從內存中卸出ReportSmith工具。一般情況下,如果應用程序只有一個報表或者只有較少的報表要輸出時,應設置AutoUnload屬性為True,如果應用程序一次要輸出多個報表,那麼要應設置AutoUnload屬性為False。
InitialValues屬性:這是一個字符串類型的屬性,它是說明報表文件中使用的變量,每一條說明一個變量。如:
ReportVAR := Value;
要詳細了解創建和使用報表變量的過程請參看創建報表一節。
TReport部件要真正執行報表功能以輸出一個報表需要調用Run方法。如下所示:
Report1.Run;
TReport部件所具有的重要方法如表15.10所示。
表15.10 TReport部件的方法
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
方法 功 能
────────────────────────────
Run 執行報表功能,輸出報表
RunMacro 發送一個宏命令給Reportimith工具
Connect 預先連接報表文件和數據庫,在輸出報表時不
需要登錄到數據庫
SetVariable 改變說明的報表變量
ReCalcReport 當報表變量改變以後,重新輸出報表
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
還有一些其他的數據訪問部件如TBatchMove部件,它主要用在兩個數據庫表之間移動或拷貝帆數據記錄,具體的使用請參看本地SQL服務器的使用。
15.8 應用舉例:多個窗體顯示同一個數據庫表
在應用當中,我們常常需要以不同的視圖顯示同一個數據庫表中的內容,例如要在兩窗體中同時顯示一個數據庫表中一個記錄的不同字段時,我們必須要想辦法使兩個窗體中的數據浏覽部件同步地顯示數據庫表中的同一條記錄的不同字段的值。要想做到以不同的視圖顯示同一個數據庫表中的記錄,下面兩條規則是很重要的:
● 多個TDataSource部件能夠同時訪問同一個數據集部件
● 在多個窗體中顯示同一個表時,必須為每個窗體設置一個TDataSource部件,只須為其中的一個窗體設置一個TTable部件
例如,如果想在窗體Form1和Form2中同時顯示一個數據庫表的記錄,最簡單可行的辦法是:為Form1和Form2各設置一個TDataSource部件叫DataSource1、DataSource2,並在Form1中設置一個TTable部件Table1,連接Form1中的Datasource1和Table1,在程序運行過程中設置Form2中的DataSource2的DataSet屬性為Form1中的Table1,代碼如下:
Format2.DataSource1.Dataset := Form1.Table1;
這樣,當Table1被打開時,兩個窗體中便可以同步地顯示數據庫表中的同一條記錄了。
一個名叫TWOForms.DPR的例子在C:\Delphi\DEMos\DB\TwoForms中(如果Delphi安裝在其它的磁盤驅動器中,從相應的磁盤驅動器中可以找到該例子),它演示了在兩個窗體中顯示同一個數據庫表的記錄。應用程序在第一個窗體中打開Contry.DB表,並在窗體中顯示Name、Captial和Continent字段,在第二個窗體中顯示Area和Population字段,在第一個窗體中有一個按鈕用於打開第二個窗體,兩個窗體中都有TDBNavigator部件,用於記錄的導航。