程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi簡單數據庫應用的創建及MASTAPP介紹

Delphi簡單數據庫應用的創建及MASTAPP介紹

編輯:Delphi

Delphi中嵌入的數據庫應用開發工具如Database Form Expert具有很強大的功能,我們不需要編寫任何程序代碼便可以快速地創建一個簡單的數據庫應用程序,甚至還能創建基於多個數據庫表的主要──明細型數據庫應用程序。

本章主要介紹用Delphi開發簡單的數據庫應用程序的一般方法和步驟,首先讓讀者對Delphi強勁的數據庫應用開發工具有一個直觀的印象,然後在此基礎上進行復雜的數據庫應用程序的設計,本章主要包括以下內容:

● 創建數據庫應用窗體

包括用Database Form Expert 或手工方式創建簡單的無需編寫程序代碼的應用程序或者利用多個部件並編寫功能復雜的程序代碼創建主要──明細型數據庫應用程序。

● 在應用程序中控制字段有關的屬性

描述怎樣讀寫數據庫表中字段的值和控制字段的顯示格式等。

本章所介紹的例子中用到的窗體、數據庫表以及相關的文件都是在安裝Delphi時缺省安裝在C:\DELPHI\DEMOS\DB\MASTAPP目錄中,並且用別名DBDEMOS表示這一子目錄。在本章例子中,除特殊聲明外,所有的TTable和 TQuery 部件的 DatabaseName 屬性都設置為DBDEMOS。

14.1 簡單的基於單表的據庫應用 

用Decphi創建顯示一個數據庫表中的內容的應用非常簡單和方便,只需要三個部件,只要將這三個部件通過相關的屬性相互聯系起來,不需要編寫任何程序代碼便可以實現。例如,用戶想查看數據庫表Customer.DB中的內容時,可以按下面步驟來實現: 

14.1.1 選擇相關的部件: 

選擇菜單Project/New開始一個新工程,並修改Form1的Caption屬性為CustomerFrom1並把Name屬性設置為CustomerForm1,然後從部件選擇板上的Data Access 頁上選取一個Datasounce部件和一個Table部件放到窗體的左上角,它們是非可見的部件,在窗體中我們看到的只是部件的圖標;從Data Control頁上選取DBGrid部件放到窗體中前兩個部件的下面。完成這些工作之後,窗體如圖14.1所示。  

圖在CustomerFrom1窗體中放置三個部件 

14.1.2 設置部件的屬性 

為了使TDBGrid部件能夠顯示數據庫表Customer.DB中的客戶信息,我們必須修改窗體三個部件相關的屬性,這些屬性的設置如表14.1所示。 

表14.1 CustomerFrom1窗體中三個部件的屬性設置

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

屬 性 屬 性 值

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

DataSource1.AutoEdit False

DataSource1.DataSet Table1

Table1.DatabaseName DBDEMOS

Table1.TableName CUSTOMER.DB

Table1.Active True

DBGrid1.DataSource DataSource1

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

這裡要注意的是:DBDEMOS是Delphi缺省安裝時C:\Delphi\DEMO\DB\MASTAPP目錄的別名,而且數據庫表Customer.DB存在該目錄下,用戶在使用這一例子時,請注意這兩項設置都是正確的。另外 Datasource1.Dataset,Table1.TableName和DBGrid1.Datasource屬性都有下拉式列表框允許用戶從可能的值列表中選擇它們的值,這樣能方便我們進行屬性的設置,而且不容易出錯。

Datasouuce1.AutoEdit屬性設置為False是為了防止用戶修改數據庫表中的數據,在下面的討論中我們將詳細地進行說明。

Table1.Active設置為True時,Delphi會打開Table1.TableName所指定的數據庫表。如果這個數據庫表不存在(或表中什麼也沒有,即空表), Delphi 會彈出出錯信息並且Table1.Active變成False。當Table1.Active被設置成True之後,Table1 部件的一些屬性就不能再修改了,如Table1.DatabaseName和Table1.Tablename屬性。若要修改它們,必須首先要將Table1.Active屬性設置為False,然後再進行修改,否則,Delphi會彈出錯誤信息“Cannot perform this operation on an open database”。當看到這個錯誤信息時,只需把Table1.Active置成False,完成相關的修改後,再把 Table1. Active 屬性設置為True。

當我們把DBGrid1.DataSource的值設置成DataSource1時,Delphi會把Customer.DB中的數據填充到DBGrid1部件中,並且可以用DBGrid1中的滾動條來浏覽數據庫表中的所有記錄。

14.1.3 運行程序 

保存文件,命名代碼單元為Cust.pas,命名工程名為CustPRJ.DPR,然後按F9編譯並運行程序。程序執行之後,我們可以使用滾動條或鍵盤移動鍵在字段和記錄間移動。但不能修改表中的數據,因為Datasouc1.AutoEdit1屬性已被設置為False。

Cust程序中的三個部件都有各自的特殊用途,三個部件的相關屬性在內部相互聯系生成最終的應用程序。TTable部件連接磁盤上的實際數據庫表和應用程序中其他部件的通道。TTable部件具有打開和關閉、讀取、更新以及其他處理磁盤數據庫文件的方法。

TDatasource部件是連接TTable部件和數據浏覽部件如TDBGrid部件的橋梁。 TDBGrid部件用於顯示數據庫表中的數據信息,它為應用程序提供一個直觀的界面。圖14.2闡述了這三個部件之間的關系。 

Cust程序中三個部件之間的內部關系 

TDBGrid 部件的奇妙之處在於它知道如何去獲取數據庫表中的下一條或前一條記錄,我們使用滾動條或箭頭鍵便可以完成這項任務。TDBGrid部件不知道如何增加、刪除和修改記錄。如果想讓 Cust 程序能夠修改數據庫表中的記錄,只要把 Datasource1 部件的AutoEdit屬性設置成True ,並重新編譯和運行程序就可以達到目的。 使用箭頭鍵, 把DBGrid的高亮度條定位到某一個字段上,然後鍵入新值,該字段中的值將被鍵入的新值所取代,並且當移動到另一條記錄時,健入的信息會自動寫入數據庫表中。如果想放棄所做的改動,只需在離開該字段前按一下Escape鍵。

如果想在表中增加新記錄,可以把高亮度條移到網格底端的空白記錄上並輸入新記錄的有關字段值。也可以在用戶指定的某一條記錄的後面插入一條新記錄,只要把高亮度條定位到指定的記錄上,按Ins鍵,使可以在該記錄的後面插入新記錄。

刪除某一條記錄時,把高亮度條定位在想刪除的記錄的任何字段上,按Ctrl+ del鍵,這時會出現保護信息,我們可以確認是否真的想刪除該項記錄。

TDBGrid為用戶提供了較完備的功能,用於控制是否編輯、增加或刪除記錄。若想禁止對數據庫表作任何修改,設置TDBGrid部件的Readonly屬性為 True , 並設置 Option.dgEDiting為False(這將為我們提供一個只讀的數據庫表浏覽器而不是數據庫編輯器,但它隱含著增加、編輯和刪除記錄的能力)。TDBGrid部件的這些屬性和Option屬性其它選項的各種不同組合可以讓我們很方便地對數據庫表進行有效的浏覽、編輯等操作。

如果我們經常使用像電子表格那樣的界面來顯示和編輯數據記錄,TDBGrid 部件便是一個很方便的工具,但那並不是最友好的用戶界面,如果想擁有更優美更直觀的界面,我們還可以使用單獨的數據浏覽部件來顯示數據庫表中各個字段的值,並利用TDBNavigator部件控制對數據庫表的存取。 

14.2 利用TDBNavigator部件創建存取程序 

我們可以改進一下Cust程序以便它一次只在對話框中顯示一個客戶的記錄信息,並用一個TDBNavigator部件控制對記錄存取──允許我們選擇一個記錄來顯示或編輯以及增加和刪除記錄。完成的應用窗體。

增強的Cust程序

14.2.1 創建應用程序窗體 

我們可以非常迅速地創建起來,因為到目前為止我們對創建窗體的方法已經比較熟悉,我們首先把所有的部件都放到窗體中,然後再設置它們的屬性。

開始一個新工程,設置窗體Form1的Name 屬性為 Customerform2 , Caption 屬性為     CustomerForm2。然後從部件選擇板上的Data Access頁上選取一個Datasource部件和一個Table部件放在窗體的右上角。再從Data Controls頁上選取DBNatvigator部件放在窗體的左上角。

窗體中其余的部件如圖14.3所示。它們是TDBEdit和TLabel部件,按圖14.3 所示創建並布置部件,分別命名DBEdit部件為EditCustno、 Editcompany 、 EditAddr1 、EditAddr2、EditCity、EditState、EditZip、EditCountry、EditPhone 、EditFAX、EditTaxRate、EditContact。

現在我們來連接TTable部件和 TDataSource 部件, 然後連接所有的數據浏覽部件和DataSource部件。設置TBNavigator部件和TDBEdit部件的屬性,它們的DataSource屬性都設置為DataSouce1。我們最後要做的事是連接窗體中各個TDBEdit 部件和它們在數據庫表中對應的字段名,通過設置TDBEdit 部件的 DataField 屬性來完成。 例如要連接命名為EditCustNo的TDBEdit部件和數據庫表中的CustNo字段,具體步驟如下:

①選中窗體中的EditCustNo部件。

②在Object Inspector窗體中,單擊DataField屬性右邊的箭頭。

③從下拉列表中選中CustNo字段名。

對窗體中的其他TDBEdit部件執行以上操作連接到其對應的字段,然後保存文件。命名代碼單元名為Cust2.pas,命名工程名為Cusprj2.DPR。 

14.2.2 使用TDBNavigator部件移動記錄指針 

上述程序運行之後,在數據浏覽部件中會顯示數據庫表中的第一條記錄。利用Tab 鍵可以在字段之間移動,但是不能編輯字段。因為我們為了防止意外修改,設置了Table1的AutoEdit屬性值為False。如果想對數據庫表中的記錄進行編輯、插入和刪除操作或者想顯示數據庫表中另一條記錄, 需要按 TDBNvigator 部件上這些功能所對應的功能按鈕。TDBNavigator部件上的按鈕和它們的功能如圖14.4所示。

TDBNavigator中的按鈕 

TDBNavigator部件的絕大多數功能都可以根據其按鈕的圖標能夠很容易地識別出來,而且TDBNavigator部件本身能感知到很多事情,如當前指針是否在數據庫表的開頭或尾部。如果用戶正在查看數據庫表中的最後一個記錄,Next和Last按鈕將會變灰成為非活動狀態。同樣,如果用戶當前正在浏覽數據庫表中的第一條記錄, TDBNavigator 上的 First 和Previous按鈕會變灰而成為非活動狀態。有關各個按鈕的作用的更詳細說明請查看聯機幫助。

如果用戶想修改當前的記錄,單擊TDBNavigator部件的Edit按鈕,然後完成需要做的修改,在做完修改之後,單擊Post按鈕以便將作的修改寫入實際的數據庫表中(更新實際的數據庫表中的記錄在數據庫術語中叫作“投寄”記錄即PostT)。如果想取消所做的修改,單擊Cancel按鈕。Cancel按鈕只取消自從上一次往數據庫表中投寄記錄以來對記錄所做的修改。例如,如果用戶曾修改了CustNo字段並單擊了Post按鈕投寄了修改,然後再修改Company字段並按Cancel,那麼只有對Company所做的修改將會被取消。也就是說,一旦修改被寫入了數據庫表中,再按Cancle按鈕是無法取消對記錄的修改的,要想恢復到以前的狀態,用戶必須要重新編輯修改記錄。值得注意的是,當用戶修改了當前的記錄,並移動到其他記錄時,TDBNavigaator部件會自動地投寄用戶對記錄的修改。例如:如果我們修改了記錄的Company字段,並沒有按Post按鈕以更新表中的記錄,而是移動到下一條記錄,這時用戶對記錄的修改也會自動地被寫入數據庫表中。

14.2.3 定制TDBNavigator部件 

TDBNavigator部件中的按鈕對我們開發人員來說是很方便的,但對於程序的最終用戶來說不一定那麼一目了然。為了幫助最終用戶或初級用戶更方便有效地使用TDBNavigator部件,我們可以設置TDBNavigator部件的ShowHint屬性為True,這樣當鼠標光標停留在TDBNavigator部件上的某一個按鈕上超過大約1秒鐘,在屏幕上便會出現該按鈕的提示信息。如果我們不想使用TDBNavigator部件本身嵌入的提示信息,我們還可以設置TDBNavigtor部件的Hints屬性,為每個按鈕指定特定的提示信息,以幫助用戶使用TDBNavigator部件。

TDBNavigator部件中有多個功能按鈕,但並不是所有的按鈕對每一個數據庫應用程序都是需要的,特別是那些不允許修改表中的數據,或修改只是在很嚴格的控制下進行的數據庫應用程序。我們可以通過設置TDBNavigator部件的 VisibleButtons 屬性來確定要在TDBNavigator中顯示哪些按鈕步顯示哪些按鈕。例如,如果我們不允許用戶修改表中的記錄,我們就不需要Add、Delete、Post、Cancel 或 Refresh 按鈕, 我們設置這些按鈕的VisibleButtons屬性為False,這樣在TDBNavigator部件中將不會出現這些按鈕。

TDBNavigator部件的ConfirmDelete屬性和Delete 按鈕配合使用對用戶刪除數據庫表中的記錄是非常有用的,當ConfirmDelete屬性設置為 True (缺省設置), 當用戶單擊Delete按鈕試圖刪除當前記錄時,Delphi會彈出一個確認框,要用戶確認是否真的想刪除當前記錄。這樣,在用戶進行刪除記錄的操作時,會更安全一些。如果用戶不希望在按下Delete按鈕時出現確認框,只要把ConfirmDelete設置為False就可以了。

還有一些屬性可以用來定制TDBNavigator部件的外觀和性能,有關這方面的詳細信息請參看聯機幫助。

14.3 創建主要──明細數據庫應用

我們前面在介紹的基於單個數據庫表的數據庫應用程序只能對數據庫表進行簡單的管理,大多數只用來浏覽單個數據庫表中的記錄信息,如果我們想浏覽多個相關的數據庫表中的記錄信息,就必須要創建主要──明細型數據庫應用程序。

在主要──明細型數據庫應用程序中,一個數據庫表作為主要表,其中存放著綜合信息,其他的數據庫表和主要數據庫表相關聯,它們當中存放著更詳細的信息。例如,當數據庫表Customer.DB作為主表,它包含著客戶的綜合信息如編號、姓名、所在公司的名稱等等。而數據庫表Orders.DB中包含著每個客戶的訂貨單的詳細信息,如訂單號、發貨日期、起運日期、發貨目的地等信息,這樣當在Customer.DB表中查看某一位客戶時,利用其中的字段CustNo與Orders.DB表發生聯系,自動地從Orders.DB表中檢索出這位客戶曾經發來的所有訂貨單的詳細信息。主要──明細型數據庫體現了關系數據庫的特點,即獨立的數據庫表之間基於它們共同的字段而發生聯系。在這裡Customer.DB和Orders.DB擁有一個共同的字段CustNo。

14.3.1 一對多關系的主要──明細型數據庫應用程序

主要和明細數據庫表之間存在一對多的關系,意思是說對於主表中的一條記錄,在明細表中有多條記錄與之對應。例如,創建一個主要──明細型數據庫應用程序,其包括兩個表Customer.DB和Orders.DB,它們分別作為主表和明細表,創建好的應用如圖14.5所示,窗體中各部件的屬性設置  

表14.2 主要──明細型數據庫應用中各部件的屬性

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

部 件 屬 性 屬 性 值 注 釋

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

Table1 Active True

(主表) DatabaseName DBDEMOS

TableName CUSTOMER.DB

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

DataSource1 DataSet Table1

AutoEdit False

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

Table2 Active True

(明細表) DatabaseName DBDEMOS

TableName ORDERS.DB

IndexFieldNames CUSTNO 指定字段CUSTNO作為

Table2中的索引字段

MasterField CUSTNO 指定與主表發生聯系

的字段

MasterSource DataSource1 說明與主表相連接的

數據源即DataSource

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

DataSource2 DataSet Table2

AutoEdit False

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

DBGrid1 DataSource DataSource1

(對應主表)

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

DBGrid2 DataSource DataSource2

(對應明細表)

TableName ORDERS.DB

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

DBNavigator1 DataSource DataSource1

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

一對多關系是非常普遍的關系。即便是簡單的名字/ 地址數據庫都有一對多的關系,因為一個人可能不止一個地址:家庭地址、工作地址、還可能有別墅地址。在本例中,公司的一個客戶常常有多個訂貨單,當我們單擊DBNavigator1中的向前、向後按鈕時,會移動DBGrid1中的記錄指針,而在DBGrid2中會自動顯示與DBGridl 中當前記錄相關的多條記錄,即顯示一個客戶的信息時,同時會顯示該客戶的所有訂貨單的詳細信息。

14.3.2 一對多──多關系的數據庫應用

前面我們介紹了基於兩個表的一對多關系的應用,下面我們介紹怎樣創建一個從三個表中浏覽數據記錄的一對多關系的應用。

例如:一個客戶也許有多張訂貨單,而每一張訂貨單中有多個訂貨項目,這樣我們在Customer.DB表和Orders.DB表之間建立一個主要──明細型關系,同時在orders.DB 表和Items.DB表之間建立一個主要──明細型關系。 

窗體中各部件的屬性如表14.3所示

表14.3 一對多──多關系的應用中各部件的屬性

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

部 件 屬 性 屬 性 值 注 釋

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

Active True

Table1 DatabaseName DBDEMOS

TableName CUSTOMER.DB

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

DataSource1 DataSet Table1

AutoEdit False

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

Active True

DatabaseName DBDEMOS

Table2 TableName ORDERS.DB

IndexFieldNames CUSTNO

MasterField CUSTNO

MasterSource DataSource1

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

DataSource2 DataSet Table2

AutoEdit False

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

Active True

DatabaseName DBDEMOS

Table3 TableName ORDERS.DB

IndexFieldNames ORDERNO

MasterField ORDERNO

MasterSource DataSource2

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

DataSource3 DataSet Table3

AutoEdit False

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

DBGrid1 DataSource DataSource3

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

DBNavigator1 DataSource DataSource1

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

窗體中其余的部件都是TDBEdit和TLabel部件,它們用於顯示Customer.DB中的字段值和Order.DB中的字段值。在該例子中,總共連接了三個表, Customer. DB 表是主要表,Orders.DB表在窗體中起到了雙重作用,它既是Customer.Db表的明細表,同時又是Items.DB表的主要表,Items.DB表是Orders.DB表的明細表。

14.4 字段對象的使用

Ttable和TQuery部件中有一個TField類型的屬性Fiedls,Fields是TField類型的對象的列表,TField對象列表是Delphi數據庫中較難以理解的一個對象,它是 TTable 部件和TQuary部件的一部分,它們是不能夠選擇到窗體中的獨立的部件,而且無論是在設計階段還是在程序運行過程中,它們都沒有可見的圖像。即使到Object Inspector窗中察看它們也很困難。

Tfield對象是在打開磁盤上的數據庫表時動態產生的,並在數據庫表被關閉時自動消失,TField對象可以控制表中的每一列是否在數據浏覽部件中顯示以及以何種格式顯示等等。通過字段編輯器(Fields Editor)我們可以建立永久性的TField 對象列表代替動態的Tfield對象列表供Delphi應用程序使用,通過Fields Editor建立的永久性的字段對象會自動地加入到程序庫單元的TForm類型定義中,它們保存在應用程序中,即使數據庫表的基本結構發生了改變,它也是一直保留著,當然如果修改後的表中使得原來所定義的字段對象不再存在,Delphi應用程序在運行過程中會給出現錯誤信息。 

14.4.1 字段對象的類型

字段對象TField對應數據庫記錄中的各個字段,因為數據庫記錄中的字段有多種數據類型,因此對記錄字段可能出現的每一種數據類型都有一個獨立的TField類型與之對應。TField的類型如表14.4所示 

表14.4 字段對象的類型

━━━━━━━━━━━━━━━━━━━━━━━━━

字段對象的類型 對應的數據類型

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

TBooleanField 布爾型數據

TCurrentyField 貨幣型數據

TStringField 字符串數據

TIntegerField 整數型數據

TBLOB 大二進制對象

━━━━━━━━━━━━━━━━━━━━━━━━━

在大多數情況下可能使用的是TStringField和TIntegerField類型的字段對象,從編程的角度來看這些TField對象的不同類型是完全相同的,應用程序是根本不必關心TField對象的實際類型,它們之間的主要區別在於:它們內部保留的以及它們和數據庫表之間傳遞的數據類型不一樣。

14.4.2 創建永久性的字段對象

我們知道字段對象在設計和運行階段都是不可見的,它既可以隨著磁盤上的數據庫文件被打開時動態地生成也可以通過字段編輯器Fields Editor來創建它。 在應用程序中使用Fields Editor可以為數據庫表中的字段創建相應的永久性的TField對象,TField 部件是不可見的部件,但是通過它,我們可以定義數據庫表中各字段的顯示屬性和顯示順序以及控制字段的取值范圍等。下面的例子,告訴我們如何使用Fields Editor定義Customer.DB表中的四字段,並在網格中顯示表中的記錄信息。

操作步驟:

1、建立一個基於 customer. DB 表的數據庫應用窗體,並在窗體中用一個網格顯示customer.DB中的全部字段,詳細方法請參見14.1節,建好的窗體如圖14.1所示。

2、設置窗體中Table1的Active屬性為True,使網格顯示表中的記錄。

3、選中Table1並雙擊鼠標左鍵,打開字段編輯器Fields Editor,缺省情況下字段列表為空。

4、單擊鼠標右鍵彈出一個彈出式菜單,然後選擇Add Fields菜單項,缺省情況下表Customer.DB中的全部字段被選進字段列表框。從字段列表框中選擇你要在網格中顯示的字段,具體做法是:單擊Custno字段,並按住CTR鍵,再單擊Company、Phone、LastInviceDate字段,然後單擊OK按鈕,確認被選擇的四個字段,時窗體中的DBGrid1中只顯示剛才被選中的四個字段值,而不再顯示表中其它的字段值。

5、改變字段的顯示順序。單擊LastInvoiceDate 字段並將它拖放到字段列表框中的第三行,即處於Company和Phone字段之間。此時窗體中顯示Customer.DB 表中記錄的字段將按新的順序顯示。

6、選擇Close按鈕,關閉字段編輯器Fields Editor。

7、按F9,運行上述程序。

14.4.2 字段對象的屬性設置

雖然字段對象是不可見的對象,但是它同樣具有很多的屬性。在程序設計階段,我們通過一定的方式可以設置它的有關屬性,下面是設置字段對象的屬性的方法和步驟。

1、選擇窗體中的table1。

2、雙擊table1,打開字段編輯器Fields Editor。

3、選擇要設置屬性的字段。

4、在Object Inspector中修改字段對象的屬性。

我們可以按上述方法設置Table1中各字段對象的有關屬性,當我們選擇Custno字段並修改其屬性,窗體內會出現對話

字段對象的屬性

修改字段CustNo的Alignment屬性為taCenter,此時網格中顯示的CustNo 字段值由原來的右對齊變成了居中。

表14.5中列出了字段對象在設計階段可以修改的屬性以及屬性說明 

表14.5 字段對象的重要屬性

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

屬 性 注 釋

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

Alignment 說明字段值的顯示方式:左對齊、右對齊、居中

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

Calculated 當該屬性值為True時,表明該字段的值是根據其它字

段的值計算得來的。否則該字段是數據庫表中的字段

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

DisplayLabel 說明字段在網格部件中顯示時的標題,缺省情況下字

段的標題就是字段名

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

DisplayWidth 說明字段在網格中顯示時所點的列寬度,即字符數

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

DisplayFormat 說明字段在顯示和編輯狀態下的顯示格式和輸入的過

and EditMask 濾條件(限定用戶輸入字段值的范圍)。

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

FieldName 在數據庫表中對應於該字段對象的字段名稱

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

Index 指定該字段對象在數據集部件中的邏輯位置,如Table1

中的第一個字段對象的Index值為0

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

Name 字段對象的名稱,缺省情況下,它是TTable、TQuery

部件的名稱加上字段的名稱。如上例中的CUSTNO字段

對象的Name屬性值為Table1CUSTNO,通過字段對象的

Name屬性可以訪問該字段的值,如Table1CUSTNO.Value

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

ReadOnly 說明該字段是否能被修改,當該屬性值為True時,該

字段的不能被修改

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

Visible 當該屬性值為True時,在與之相連的網格部件中將不

顯示該字段

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

根據表14.5中的屬性,我們可以修改上例中一些字段的某些屬性, 使網絡中顯示表Customer.DB中的記錄更符合我們的工作習慣。修改的屬性如表14.6所示,經過修改後的程序運行結果如圖14.10所示。

表14.6 修改後的字段對象的屬性

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

字 段 屬 性 屬 性 值

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

CustNo DisplayLabel 客戶編號

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

Company DisplayLabel 公司名稱

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

Phone DisplayLabel 電話號碼

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

LastInvoiceDate DisplayLabel 購買日期

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

修改字段對象的屬性

14.4.4 字段對象的訪問

字段對象在應用程序中有動態生成的,也有通過字段編輯器Fields Editor 創建的永久性的,它們雖然在設計和運行階段都是不可見,但是它們跟其他的對象一樣都擁有自己的屬性、方法和事件,因此我們在應用程序中是可以對字段對象進行控制和訪問的。

因為動態字段對象是沒有自己的名字的,永久性的字段對象有自己的名字,所以對這兩種字段對象的訪問方法是不一樣的。

14.4.4.1 動態字段對象的訪問

動態字段對象存在於數據集部件TTable和TQuery部件中,它們是隨著磁盤上的數據庫文件的打開而動態生成的,並且每一個字段對象對應於數據庫表中的一個字段(即記錄的一列),TTable或TQrery部件中所有的字段對象存在屬性Fields列表中,Fields列表中的字段對象就像數組元素一樣擁有自己的索引號,我們可以用這個索引號來訪問字段對象。索引號在程序運行時賦值,從0開始,表中最左邊的一列(第一個字段)的索引號為0,緊接著右邊一個為1,以此類推。訪問這些屬性的方法和處理其他對象一樣。 

Table1.Fields[0].DisplayLabel:='標識符'

上述代碼讓我們訪問與Table1相連的數據庫表中的第一個字段,並為該字段指定一個標題,這是通過設置它的DisplayLabel屬性值為一個特定的標識符來實現的。

通過索引號來訪問Fields屬性中的字段在使用For循環對列號進行迭代時會非常有用。但是在大多數簡單應用程序中,通過列名(字段名)來訪問字段會更加明白而且易讀。在TTable部件中,提供了一個名為FieldByName的方法以便讓我們通過列名訪問字段對象。

Table1.FieldByName('CustNo').DisplayLabel:='標識符'

通過這種途徑同樣可以訪問CUSTOMER.DB表中的CustNo字段,並為該字段指定一個標題信息。

現在我們可以建立一個允許用戶通過字段名和索引號來訪問Customer.DB 表中的字段對象的簡單窗體。

字段對象的訪問

在該應用窗體的運行過程中,我們通過程序來訪問其中的字段對象並設置有關的屬性,這一控制過程我們放在窗體的OnCreate事件處理過程中。

例14.1 在窗體的Oncreate事件處理過程中訪問字段對象。

procedure TForm1.FormCreate(Sender:TObject);
Begin
with Table1 Do
begin
{通過索引號訪問字段對象}
Field[0].DisplayLabel:='客戶編號';
{通過字段名訪問字段對象}
FieldByName('Company').DisplayLabel:='公司名稱';
FieldByName('Phone').DisplayLabel:='電話號碼';
FieldByName('LastInvoiceDate').DisplayLabel:='購買日期';
end;
end;
  

在程序運行過程中訪問字段對象 

14.4.4.2 永久性字段對象的訪問 

通過字段編輯器Fields Editor 建立的永久性字段對象的訪問相對於動態字段對象的訪問要簡單得多,我們在程序中可以直接通過字段對象的名稱(即Name屬性)進行訪問。

例如:

Table1CustNo.DisplayLabel:='客戶編號';

Table1CustNo.DisplayWidth:=12;

14.4.4.3 字段對象的讀取和賦值 

通過字段對象的Value屬性,我們可以讀取字段對象的值,例如在如圖14.13所示的窗體中,單擊Read按鈕便可以將Customer.DB表中當前記錄的COMPANY字段的值讀取到編輯框Edit1中。 

讀取字段對象的字段值

窗體中各部件的屬性如表14.7所示 

表14.7 各部件的屬性

━━━━━━━━━━━━━━━━━━━━━━━━

部件的屬性 屬 性 值

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

Button1.Caption &Read

Button1.Name Button1

Label1.Caption 字段值

Label1.Name Label1

Edit1.Text

Edit1.Name Edit1

━━━━━━━━━━━━━━━━━━━━━━━━

其它部件的的屬性跟前面的例子一樣。

為Read按鈕編輯的OnClick事件處理過程如下:

procedure Form1.TButton1Click(Sender:TObject);
begin
Edit1.Text:=Table1Company.Value;
end;

在這裡要注意的是:從字段對象中讀取字段值時必須要將它賦給與之數據類型相匹配的變量,否則會出錯。在上面的程序代碼中,Table1Company的類型是TStringField 即是字符串類型的字段,而編輯框Edit1的屬性Text的類型也是字符串型的,因而它們是匹配的。如果類型不匹配,則要經過一定的轉換才能夠相互賦值。如: 

在運行過程中我們通過程序代碼來設定字段Phone的顯示格式,美國的電話表示形式與中國的表示形式不一樣(如美國808-555-0269,中國(808) 5550269 ), 為此我們將phone 字段的值表示成中國式的形式。具體方法是:在 Object Inspector 中選取Table1phone對象,並為此對象的OnGetText事件編寫如下程序代碼:

TForm1.Table1PhoneGetText(Sender:TField;
Text:OpenString;DisplayText:Boolean);
begin
If DisplayText then
begin
Text:=Table1Phone.Value;
Delete(Text,4,1);
Delete(Text,7,1);
Insert('(',Text,1);
Insert(')',Text,1);
end;
end;

圖14.14 設定字段對象的顯示格式

14.4.6 自定義字段以及計算字段對象的創建

有時候為了使應用程序完成所期望的工作,我們要在數據庫表現有字段的基礎上增加一些自定義的字段,這些字段並不是數據庫表中實際存在的字段,它們常常是根據數據庫表中的其它的字段動態地計算出來的,因而它們常常被稱為計算字段。

例如我們創建一個浏覽ORDERS.DB表中記錄的應用如圖14.15所示。

浏覽ORDERS.DB表中的記錄

首先,我們想在顯示OREDRES.DB表的網格中增加一個自定義的字段對象,完成以下步驟:

1、雙擊窗體中的Table1,打開字段編輯器Fields Editor。

2、在Fields Editor窗口中,單擊鼠標右鍵,選擇New Fields菜單項。

3、Delphi顯示New Fields對話框。選擇Field Type列表框中的Currency 項,並在Field Name文體框中輸入Balance , 這樣我們自定義了一個 CurrencyField 類型的字段Balance。Delphi會自動地填入相應的字段對象名,其缺省值為Table1Balance。如圖14.16所示。 

圖14.16 New Field 對話框

4、單擊Ok按鈕,關閉New Field對話框。當Fields Editor 窗口重新出現時, 注意Balance已經出現在Fields列表框中。

5、在Fields Editor 窗口中單擊鼠標右鍵, 並選擇 Add Fields 菜單項,打開AddFields對話框。

6、從Available Fields 列表框中, 按住 Ctrl 鍵並單擊鼠標左鍵,選擇字段:

OrderNo、CustNo、SaleDate、ShipData、ItemsTotal、Amountpaid以及Balance.

7、單擊OK按鈕,關閉Add Fields對話框,得到如圖14.17所示的Fields Editor窗口。

圖14.17 字段編輯器Fields Editor

8、雙擊Fields Editor的控制盒關閉字段編輯器Fields Editor。

至此我們已經為Table1創建了一個自定義的字段對象Balance,下面我們把Balance字段設置成計算字段對象,使其顯示每一個客戶的現金余額,即此字段的值是由ORDERS. DB表中ItemsTotal和Amountpaid字段的值計算而來的。為使應用程序實現這種計算功能,完成以下步驟:

1、在Object Inspector中選擇自定義字段對象Table1Balance,修改其 Calculated屬性值為True。即定義Balance字段為計算字段。

2、在Object Inspector窗口中,選擇Table1部件的Event頁。

3、雙擊OnCalcField事件,為Table1OnCalcField編寫事件處理過程如下:

procedure TForm1.Table1OnCalcFields(DataSet:TDataSet);
begin
Table1Balance.Value:=Table1ItemsTotal.Value-Table1AmountPaid.Value;
end;

浏覽ORDERS.DB 中的記錄

14.5 查詢數據庫中的記錄

數據庫中儲存著大量的數據信息,如何充分有效地查詢其中的數據,對用戶而言是至關重要的。如果想查詢數據庫,首先要確定要查詢的字段要麼是數據庫表中的關鍵字段,要麼是輔助索引。如果我們查詢的是Paradox或dBASE數據庫系統中的表,這是唯一的選擇。

一般而言,查詢數據庫中的記錄的方法有兩種:Gotokey方法和Findkey方法。兩種方法十分相似,主要區別在於我們如何指定查找值。這兩種方法的思想是在指定列(字段)中尋找指定的查找值,如果在數據庫表中找到了這個值,表中的記錄指針便指向該記錄,這樣我們便查詢到了我們需要的記錄,進而可以訪問找到的記錄中的各項數據。 

14.5.1 使用GotoKey方法查找數據記錄

使用Gotokey方法查詢數據庫中的記錄的具體步驟如下:

1、確保要查找的字段是關鍵字或已經為它定義了輔助索引,並保證TTable部件的屬性列表中有關鍵字段名或輔助索引名。

2、通過調用GotoKey方法,把要查找的TTable部件置成查找模式。

3、把查找值送進被查找的Field的查找緩沖區。

4、調用TTable部件的GotoKey方法,並測試它的返回值判斷查找是否成功。

如果查找成功,GotoKey返回一個True值,並且表中的記錄指針指向找到的記錄。如果查找失敗,GotoKey返回False,表中的記錄指針不發生變化。

在這裡要注意的是如何給Field的查找緩沖區賦值,我們知道字段對象是不可見的對象,它們沒有自己的名字,在大多數情況下,要使用TTable部件的FieldByName 方法到字段列表中查找字段對象以便為它賦值。但字段緩沖區也是沒有名字的,當TTable部件處於查找模式時,我們只要把查找值賦給字段對象的AsString屬性就可以了。AsString的作用不只是它的表面意思。它是一個轉換屬性,任何賦給字段對象的AsString屬性的字符串都將轉換成該字段對象應於數據庫表中的字段的數據類型。當然AsString不能將查找值轉換成BLOB、Bytes、Memo和Graphic類型的數據,用戶一般也不會查找這種數據類型的字段。

下面便是說明使用Gotokey方法查找數據記錄的例子。

例14.3 當用戶在Edit1部件中輸入客戶號碼並單擊查找按鈕,程序便開始在Table1中查找這個客戶號。如果查找成功,查找信息“查找成功”便會顯示在標簽Label1上,被查詢到的客戶的電話號碼顯示在標簽Label2上。表中的記錄指針將轉移到該客戶記錄處。並且在網格DBGrid1中以高亮度顯示這一條記錄。  

查詢數據庫中的記錄

下面的程序清單是查詢按鈕上的OnClick事件的處理程序,它是使用Gotokey方法查找數據庫中的記錄的。

procedure TForm1.Button1OnClick(Sender:TObject);
begin
with Table1 do
begin
Label1.Caption:=' ';
Label1.Caption:=' ';
IndexFieldName:='CustNo';
setkey;
FieldByName('CustNo').AsString:=Edit1.Text;
If GotoKey then
begin
Label1.Caption:='查找成功';
Label1.Caption:=FieldByName('Phone').AsString;
end;
else
Label1.Caption:='查找失敗';
end;

查詢數據庫中的記錄

14.5.2 使用FindKey方法查找數據庫中的記錄 

雖然使用上面的Gotokey方法在數據庫中查找記錄效果不錯,但是Delphi 還提供了一種更加容易的查找方法,這就是Findkey方法,兩種方法雖然很相似,但是Findkey方法更簡單明了一些。

例14.4 我們可以使Findkey方法代替上面例子中的處理程序,下面是程序代碼:

procedure TForm1.Button1OnClick(Sender:TObject);
var
SeekValue:string;
begin
with Table1 do
begin
Label1.Caption:=' ';
Label1.Caption:=' ';
IndexFieldName:='CustNo';
SeekValue:=Edit1.Text;
If FindKey([SeekValue]) then
begin
Label1.Caption:='查找成功';
Label1.Caption:=FieldByName('Phone').AsString;
end;
else
Label1.Caption:='查找失敗';
end;

Findkey方法和Gotokey方法的根本區別在於查找值要作為參數傳遞給Findkey 函數。而GOtokey是不帶參數的,它假定用戶已經把查找值賦給了代表著被查找到的字段的查找緩沖區。

Findkey接受的參數是放在方括號中的,是用逗號分開的查找值數組。數組中的每一個值都對應於特定列的查找值,即參數中允許有多個查找值,Findkey 允許用戶同時查找數據庫表中的多個列。上面的程序清單中的Findkey函數只接受了變量Seekvalue這一個查找值,這個查找值對應表中的字段CustNo,CustNo是表中的關鍵字段。如果要同時查找表中的多個字段,必須把要查找的多個字段名賦給TTable部件的IndexFieldName屬性,並用逗號分開各字段,然後把每個字段的查找值賦給Findkey的參數數組中。 

14.5.3 利用GotoNearest和FindNearest執行不精確查找

在我們上面討論的查找中,要麼查找成功要麼查找失敗,因為我們查找的是特定查找值的一個精確匹配值。Delphi還提供了一種查找方法,即不精確查找,這樣的查找絕對不會失敗,它總是給用戶查找出一個結果來,也許這結果並不是用戶需要的,但這個查找出來的結果是最接近用戶要求的。在Delphi中是利用GotoNearest和FineNearest兩種方法來執行不准確查找的,它們總是從數據庫中查找出與查找值最接近的匹配值。如果它們查找到與查找值精確匹配的值,那當然最好不過了,如果他們找不到精確匹配的值,它們就會把與用戶指定的查找值最接近的記錄提交給用戶。

GotoNearest的使用方法和Gotokey一樣,FindNearest的使用方法和Findkey一樣。跟Gotokey一樣,使用GotoNearest時必須要把查找值賦給字段的查找緩沖區,兩者的不同之處在於查找值的說明方式不一樣,使用GotoNearest時,說明的查找值可以是完整的也可以是不完整的,如果要對'Dunteman'進行不精確查找,在給字段的查找緩沖區賦查找值時,可以使用'Dunteman'、'Dun'或者`Du'作為查找值,這樣查找出來的結果會盡可能地接近這個值的。

如果沒有找到與用戶指定的查找值精確匹配的記錄,Delphi會調整記錄指針並停留在與查找值最接近的第一個記錄上。例如如果查找`Dunteman'時,沒有找到精確匹配的值,記錄指針可能會停留在`Dunwoody'上或者停留在更遠一些的'Event'上;如果查找'Du' 沒有找到精確匹配的值,記錄指針可能停留在‘Duncan’上,甚至‘Dunteman'之前,總之Delphi會自己地調整記錄指針,使之指向最接近查找值的記錄並將該記錄作為查找的結果提交給用戶。

GotoNearest和FindNearest都返回一個Boolean值以表明查找是否成功。它們一般都是成功的,它們總是要把記錄指針移到某處。

下面的例子是用GotoNearest方法進行不精確查找。

例14.5 創建好的窗體,在編輯框中輸入一個不完整的客戶所在的公司名稱,並且按“不精確查找”按鈕,然後觀察一下查找的結果並注意記錄指針指向那一條記錄。反復試驗幾次便會理解GotoNearest是如何工作的。

利用GotoNearest方法執行不精確查找

窗體中的“不精確查找”按鈕的事件處理過程代碼如下:

procedure TForm1.Button1Click(Sender: TObject);
begin
with table1 do
begin
IndexFieldNames:='Company';
setkey;
FieldByName('Company').AsString:=Edit1.text;
GotoNearest;
label3.caption:=FieldByName('Company').AsString;
end;
end;

讀者可以利用 FindNearest 方法執行上面的不精確查找, 具體使用方法可以參看Findkey方法的使用。

在上面的例子中要設置table1的IndexFieldNames屬性為Company。

GotoNearest方法進行不精確查找

14.6 修改數據庫中的記錄

我們掌握了字段對象的概念和如何查找數據庫中的記錄之後,下面我便可以很方便地修改數據庫中現存的記錄了,一般來說,在程序中修改數據庫中的記錄包括下面這些步驟:

1、在數據庫中找到要修改的記錄,並將記錄指針移至該記錄。

2、調用Edit方法將與數據庫表相連的TTable部件設置成編輯狀態。

3、修改一個或多個字段。

4、調用post方法將修改後的記錄寫入數據庫。

以上這幾個步驟只是概述性的,具體實現時還有很多細節需要留心,我們通過一個例子來演示上面的全過程,以便讓讀者進一步地了解和掌握修改記錄的方法。

例14.6 我們為四個按鈕分別編寫了事件處理過程,用來遍歷數據庫中的記錄並對每個客戶記錄的Company字段進行修改,在程序對記錄進行更新操作時窗口中的控件都是無效的,在這個例子中我們還編寫了一個簡單的異常代碼塊用來確保在更新過程中出現異常時使控件恢復正常操作。 

修改數據庫記錄

14.6.1 Edit方法Post方法

為了能讓用戶通過程序修改數據庫表中的記錄,TTable部件必須要處在編輯狀態下。在大多數情況下,數據庫表都是以浏覽(只讀方式)方式打開的,也就是說它的每一個字段可以被讀取介不能被編輯修改。調用Edit 方法能夠將 TTable 部件置成編輯狀態, 當TTable部件處於編輯狀態後,我們才可以通過程序修改當前記錄指針所指向的記錄,但這樣修改後的記錄不會立即被寫入到磁盤上的實際數據庫表中。要想保存對記錄的修改,必須要調用Post方法,Post方法才真正將我們對記錄的修改寫入實際的數據庫表中。

一般來說,用來掃描整個數據庫表並修改每個記錄的某一個字段的程序如下所示:

with Table Do
begin
DisableControls;{在修改記錄的過程中,使其它部件無效}
First; {將記錄指針指向第一條記錄}
while not EOF do
begin
<讀取記錄的一個字段值到一個變量中>
<做適當的修改>
Edit; {將TTable部件置成編輯狀態}
<將修改後的字段值寫回到其對應的字段>
post; {將修改後的記錄寫回數據庫}
next; {修改下一條記錄}
end;
enablecontrols; {恢復其它部件的功能}
end;

程序都是對TTable部件進行操作,因此使用With語句來防止錯誤的擴散是很有意義的。在這裡要注意Disablecontrols方法和EnableControls方法的使用。DisableControls方法是在程序修改TTable部件中的記錄時,切斷TTable部件與數據訪問部件TDatasource 部件的聯系。否則,在對TTable中的每一修改之後,TDataSource 部件都會更新窗體中所有數據浏覽部件的顯示內容,這樣會急劇減慢處理過程而且浪費時間。EnableControls方法是與DisableControle方法執行相反的操作,它是用來恢復TTable部件與TDatasource部件的聯系並促使所有的數據浏覽部件更新顯示。

調用First方法是將記錄指針移到數據庫表中的第一條記錄,確保程序從表中的第一條記錄開始進行修改。調用Next方法是將記錄指針從當前的記錄移到下一條記錄,這樣保證了從表中的第一條記錄開始逐條記錄進行修改,直到修改完最後一條記錄。如果不調用Next方法,程序將會陷入無窮的死循環。 

14.6.2 實現異常保護的TRY...FINALLY語句

上面的程序存在著潛在的危險,在實際應用過程中,可能因為某些原因使得對數據庫表的更新不能進行下去。如當程序試圖執行Post方法將修改後的記錄寫回磁盤時,而又因為某種原因磁盤沒有准備好,這時便出現了異常。當出現異常時,應用程序會暫停下來並且會彈出一對話框顯示有關的錯誤信息,在用戶單擊錯誤信息對話框之後,程序將繼續執行到某一個地方去,而這個地方常常不是用戶所能預料到的。在我們的程序中, 在執行Post方法之前,窗體中所有的部件與TTable部件都已失去聯系。因此,這種異常將導致窗體中顯示的數據和數據庫無關。

Object Pascal中的Try...Finally語句為我們解決上述異常問題提供了一個解決方法。在Delphi中仍然采用了這一語句用來處理異常問題。實際上,Try...Finally 語句是把兩組語句組合在一起。語句的Try部分包含了可能產生異常的程序代碼,Finally部分包含了即使發生了異常也必須執行的一條或多條語句。在本例中, Finally 部分只包含了EnableControls方法調用這一條語句,我們將前面的代碼改寫並組合進Try...Finally 語句: 

with Table Do
begin
DisableControls;{在修改記錄的過程中,使其它部件無效}
Try;
First; {將記錄指針指向第一條記錄}
while not EOF do
begin
<讀取記錄的一個字段值到一個變量中>
<做適當的修改>
Edit; {將TTable部件置成編輯狀態}
<將修改後的字段值寫回到其對應的字段>
post; {將修改後的記錄寫回數據庫}
next; {修改下一條記錄}
end;
enablecontrols;
Finally;{出現異常時,執行下面的程序}
enablecontrols; {恢復其它部件的功能}
end; {結束Try...Finally語句}
end;

在保留字Try和Finally之間的代碼跟前面的代碼是一樣的,它們用於在記錄之間移動記錄指針並處理對記錄的修改,這一段代碼可能會出現異常,當異常發生時,我們想保證執行EnableControls,以便窗體中各控件恢復與 TTable 部件的聯系, 因此我們必須將EnableControls語句放在Finally和結束語句End之間。

在這裡要特別注意,請讀者們不要混淆了Try...Finally語句和Try...Except 語句。如果真正想在發生異常時采取相應的處理,就要使用Try...Except語句。Try... Finally語句只是用來處理當異常出現時,使應用程序執行Finally部分的語句,使程序繼續執行下去。Try...Except語句是實現異常處理,Try...Finally語句是實現異常保護。

有了上述這些概念,我們便可以提供這個例子的一些程序代碼,它涉及了所有這些內容。

程序清單:修改數據庫中的記錄

unit Unit26;
interface 
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, DBGrids, ExtCtrls, DB, DBTables, Buttons;
type
TForm1 = class(TForm)
DataSource1: TDataSource;
customerTable: TTable;
Panel1: TPanel;
DBGrid1: TDBGrid;
Panel2: TPanel;
UpperCaseFirstAddBtn: TButton;
UpperCaseSecondAddBtn: TButton;
MixedCaseFirstAddBtn: TButton;
MixedCaseSecondAddBtn: TButton;
BitBtn1: TBitBtn;
procedure ForceCase(TargetField:String;ToUpper:Boolean);
procedure UpperCaseFirstAddBtnClick(Sender: TObject);
procedure MixedCaseFirstAddBtnClick(Sender: TObject);
procedure UpperCaseSecondAddBtnClick(Sender: TObject);
procedure MixedCaseSecondAddBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; 
var
Form1: TForm1; 
implementation
const
upper=true;
Mixed=False;
{$R *.DFM}
Function IsUpper(ch:char):Boolean;
begin
If (ch>='A')and(ch<='Z')then
IsUpper:=true
else
IsUpper:=False;
end;
procedure TForm1.ForceCase(TargetField:String;ToUpper:Boolean);
var
WorkBuffer:string;
i:Integer;
begin
with customerTable do
begin
DisableControls;
TRY
First; {將記錄指針移到第一條記錄處 }
While not EOF do
begin
WorkBuffer:=FieldByName(TargetField).AsString;
If ToUpper then
for i:=1 to Length(WorkBuffer)do
WorkBuffer[i]:=UpCase(WorkBuffer[i])
else
begin
for i:=1 to Length(WorkBuffer) do
If IsUpper(WorkBuffer[i]) then
WorkBuffer[i]:=chr(ord(WorkBuffer[i])+32);
WorkBuffer[1]:=UpCase(WorkBuffer[1])
end;
Edit;
FieldByName(TargetField).AsString:=WorkBuffer;
post;
Next;
end;
Finally
enableControls;
end;
end;
end; 
procedure TForm1.UpperCaseFirstAddBtnClick(Sender: TObject);
begin
ForceCase('Addr1',Upper);
end; 
procedure TForm1.MixedCaseFirstAddBtnClick(Sender: TObject);
begin
ForceCase('Addr1',Mixed);
end;
procedure TForm1.UpperCaseSecondAddBtnClick(Sender: TObject);
begin
ForceCase('Addr2',Upper);
end;
procedure TForm1.MixedCaseSecondAddBtnClick(Sender: TObject);
begin
ForceCase('Addr2',Mixed);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
customerTable.open;
end; 
end.

14.7 插入和刪除記錄

雖然我們使用DBD或者在應用程序窗體中用TDBNavigator可以插入、刪除表中的記錄,但是任何重要的數據庫應用程序都是根據最終用戶的命令完成此類操作的。同樣,如果我們掌握了字段對象及其用法,修改數據庫中的記錄,插入和刪除記錄將變得非常容易。

要想刪除表中的某一條記錄,首先將記錄指針移到該記錄處,然後調用delete方法,這樣,當前指針所在的記錄就會被刪除,而且我們在進行刪除操作時,不必將TTable部件設置成編輯狀態。當前指針所在的記錄被刪除之後,被刪除記錄下面的所有記錄都向前移動,記錄指針自動移到緊挨著被刪除的記錄的下一條記錄。在刪除記錄的過程中沒有提醒用戶是否真的想刪除當前記錄的信息確認框,因此在進行此項操作時要倍加小心,如果是開發應用程序,最好的辦法是提供一個確認信息框確保用戶不會意外刪除記錄。

插入一條記錄也很簡單,Delphi為用戶提供兩種方法用來插入記錄到現存數據庫表中,一種方法是在當前記錄指針所在的記錄處插入記錄;另一種方法是在數據庫表的尾部插入記錄。這兩種方法是分別調用Insert方法和Append方法實現的。但是無論是調用Insert方法還是調用Append方法在具有索引的數據庫表中插入記錄,增加到索引表中的記錄都將按照索引順序寫入到數據庫表中,也就是說對於索引表,調用Insert和Append方法的效果是一樣的。事實上,Append方法只適用於那些沒有索引的表,這種沒有索引的表並不十分有用因而通常不創建這種表。幾乎任何情況下我們都是用Insert方法來插入記錄。

用戶在插入記錄時一般可以采用兩種方式插入:逐步插入即首先建立一條空記錄,然後再填充記錄的各個字段,最後再將記錄寫回到磁盤,共分三個獨立的操作步驟;而使用InsertRecord方法便可以一次將插入記錄的操作完成。 

14.7.1 逐步插入方法

逐步插入方法分為三個明確的步驟:先調用TTable部件的Insert方法在TTable中創建一條新的空記錄,然後填充該記錄的各個字段,最後調用post方法把新記錄寫到磁盤上的實際數據庫文件中,在填充並傳送記錄以前,考慮插入記錄到表中的什麼位置是毫無意義的,假設插入的表是有索引的,在調用post方法時,Delphi會自動地把插入的新記錄按照索引順序插入到表中的正確位置。如果插入的表中沒有索引,那麼新記錄將插入到當前指針所在記錄的後面。

因此,采用逐步插入方法插入記錄的程序代碼一般如下形式:

With Table do
begin
Insert; {插入一條空白記錄}
<填充該記錄的各個字段>
post; {將插入的記錄寫回到磁盤文件}
end;

對於沒有索引的數據庫表,可以用Append方法替代Insert方法把新記錄插入到表的尾部。

14.7.2 調用InsertRecord插入記錄

對於簡單的應用程序,Delphi允許用戶用一條語句插入一個新記錄,而且這個新記錄可以帶有任意多個新字段值。InsertRecord方法把新記錄中字段的賦值語句和psot方法調用組合進一條語句中。

InsertRecord方法把記錄的各個字段值組合成一個字段值數組作為它的唯一參數。在字段值數組中,可以為插入的記錄的每個字段提供一個字段值,或從最左一列開始依次為任意多個字段賦值。也就是說用戶可以從表的最左邊一列起, 把多個列的值同時傳遞給InsertRecord,直到所有字段都被賦值。用戶也可以省略後面的字段,InsertRecord會用空值填充這些沒有賦值的字段。用戶還可以對那些明確希望用空值填充的字段傳遞保留字NIL來標明該字段為空。

如我們希望在Customer.DB表中插入一條記錄,可以用下面的代碼來實現:

InsertRecord(['2000',NIL,NIL,NIL]);

在上面的程序代碼中,我們只填充了四個字段:CustNo、Company、Add1 、 Add2 。InsertRecord會自動將其它字段賦以空值。

例14.7 在這個例子中,我們在CustNo.DB表中插入和刪除記錄,都是在程序中完成這類操作的,而不再是使用DBD或數據浏覽部件完成。

插入/刪除記錄

程序清單:

unit tt;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
StdCtrls, Forms, DBCtrls, DB, DBGrids, Buttons, DBTables, Grids,
ExtCtrls,Mask,Dialogs;
type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
DBNavigator: TDBNavigator;
Panel1: TPanel;
DataSource1: TDataSource;
Panel2: TPanel;
customerTable: TTable;
BitBtn1: TBitBtn;
Label1: TLabel;
Label2: TLabel;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
CustNoEdit: TEdit;
CompEdit: TEdit;
procedure FormCreate(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn3Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
customerTable.Open;
end;
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
If (Length(CustNoEdit.text)=0)and
(Length(CompEdit.text)=0)
then
MessageDlg('沒有輸入新記錄的字段值!',mtError,[mbCancel],0)
else
with customerTable do
begin
IndexFieldNames:='CustNo';
If FindKey([CustNoEdit.text]) then
MessageDlg('已經存在這條記錄!',mtError,[mbCancel],0)
else
InsertRecord([StrToInt(CustNoEdit.text),CompEdit.text,nil]);
CustNoEdit.text:=' ';
CompEdit.text:=' ';
end;
end;
procedure TForm1.BitBtn3Click(Sender: TObject);
begin
If (Length(CustNoEdit.text)=0)and
(Length(CompEdit.text)=0)
then
MessageDlg('沒有輸入刪除的記錄的字段值!',mtError,[mbCancel],0)
else
with customerTable do
begin
IndexFieldNames:='CustNo';
If FindKey([CustNoEdit.text]) then
begin
If MessageDlg('你確定要刪除這條記錄嗎?',mtConfirmation,
[mbYes,mbno],0)=mrYes then Delete;
end
else
MessageDlg('沒有你要刪除的記錄!',mtError,[mbCancel],0);
CustNoEdit.text:=' ';
CompEdit.text:=' ';
end;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
CustNoEdit.setfocus;
end; 
end.

14.8 輸入數據的有效性驗證

當用戶向一個數據庫表中插入新記錄或修改原有記錄時,我們必須確保用戶輸入的數據是有效的,為此Delphi通過三種不同的途徑用來驗證用戶輸入的數據是否有效。

這三種途徑是:基於數據庫表的有效性驗證、基於字段的有效性驗證、基於記錄的有效性驗證。

基於數據庫表的有效性驗證:

在用戶創建數據庫表時就建立有效性驗證機制,如在使用DBD創建一個表時,我們可以為創建的數據庫表說明一些驗證手段,包括字段的最大值,最小值,圖形字段的顯示格式等等。在設定這些有效性驗證機制時,不需要編寫任何程序代碼。基於數據庫表的有效性驗證是當數據寫到數據庫之前,由數據庫本身來執行。Delphi也執行一些有效性驗證,如在數據寫到數據庫之前Delphi會驗證每一個字段是否被填入相應的值,有關這種途徑來驗證數據的有效性的詳細情況請參考DBD的使用。

基於字段的有效性驗證:

一般有兩種方法來進行這種方式的有效性驗證。

①為記錄中需要設置有效性驗證的字段編寫Onvalidate事件處理過程。這樣每當該字段的值被修改時,該字段的OnValidate事件處理過程就會被調用,進而對被修改的字段值進行驗證。

②對於記錄中要求非空的字段(如口令或關鍵字等),我們必須首先設置這些字段的Required屬性為True,然後為這些字段編寫OnValidate事件處理過程,這樣在修改現存記錄或插入新記錄時,在寫入數據庫之前,如果要求非空的字段中沒有填入適當的字段值,那麼會出現錯誤信息提示用戶必須輸入字段值。

基於記錄的有效性驗證:

這種驗證方式一般在TTable部件的BeforePost事件處理過程中進行處理,即在記錄寫回到數據庫之前對記錄的每個字段值進行有效性驗證。

例14.8 在程序中對字段值的有效性進行驗證。

1. 創建一個用TEdit部件浏覽ORDERS.DB表的應用,如圖14.25所示。

2. 修改TDataSource部件的AutoEdit屬性為True。

3. 雙擊TTable部件打開字段編輯器Fields Editor,並單擊SaleDate字段。

4. 在Object Inspector中雙擊SaleDate字段對象的OnValidate事件,為該字段對象編寫事件處理過程如下:

TForm1.Table1SaleDateValidate(Sender:TField);
begin
If SaleDate.Value>Now then
raise Exception.Create('不能輸入一個未來的日期');
end;

當這個應用程序運行時,用戶修改或插入ORDERS.DB中的記錄時,該應用程序會對銷售日期(SaleDate)字段的值進行驗證,該字段值不能晚於系統的當前日期,程序中調用Now方法獲得系統的當前日期。如果字段值大於系統的當前日期會出現一錯誤信息提示框,告知用戶不能輸入一個未來的日期。

使用TDBComBox部件和TDBLookupComBox部件來限制用戶輸入字段值的范圍。

創建查看orders.db表的應用,創建好的窗體如圖14.25所示。窗體中顯示Terms 字段的是TDBComBox部件,顯示EmpNo字段的是TDBLookupComBox部件。 

圖14.25 用數據浏覽部件限制用戶的輸入

TDBComBox和TDBLookupComBox部件的屬性值如表14.8所示:

表14.8 窗體中各部件的屬性設置

━━━━━━━━━━━━━━━━━━━━━━━━━━━

部 件 屬 性 屬 性 值

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

DataField Terms

DBComBox1 DataSource DataSource1

Items Prepaid

Net 30

COD

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

DataField EmpNo

DataSource DataSource1

DBLookupComBox LookupSource DataSource2

KeyField EmpNo

LookupField EmpNo

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

DataSource1 DataSet Table1

AutoEdit True

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

DataSource2 DataSet Table1

AutoEdit True

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

Table1 DatabaseName DemosDB

TableName orders.db

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

Table2 DatabaseName DemosDB

TableName orders.db

━━━━━━━━━━━━━━━━━━━━━━━━━━━

該應用運行時,當用戶修改和插入記錄到ORDERS.DB表中時,Terms字段的值可以從組合框中的Prepaid、Net30、COD三個值中任選,EmpNo字段的值是從另一個表Employee中獲得的雇員號碼,用戶可以從中選擇。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved