多層數據庫開發十二:使用數據控件

 http://www.cnblogs.com/m0488/p/3304605.html

第十二章 使用數據控件

  在數據庫應用程序中,數據控件是經常要用到的。與前面介紹的數據集構件如TTable、TQuery、TStoredProc、TClientDataSet不同的是,數據控件都是可視的。也就是說,如果修改了這些構件的屬性,能在窗體上馬上反映出來。如果這些構件的Enabled屬性設爲True並且數據集的Active屬性也設爲True,在設計期就可以看到數據。
12.1 Delphi 4中有哪些數據控件
  在Delphi 4的IDE中,數據控件都位於構件選項板的“Data Controls”頁上。下面簡單介紹這些數據控件:
.TDBGrid以行和列組成的柵格顯示數據。
.TDBNavigator用於對整個數據庫的記錄進行導航,如向前翻一個記錄、向後翻一個記錄、翻到第一個記錄、翻到最後一個記錄等。
.TDBText把字段的內容作爲標籤顯示。
.TDBEdit以編輯框的形式顯示一個字段的內容。
.TDBMemo以多行文本編輯器的形式顯示備註字段的內容。
.TDBImage用於顯示數據庫中的圖像字段。
.TDBListBox以列表框的形式顯示數據。
.TDBComboBox以組合框的形式顯示數據。
.TDBCheckBox以複選框的形式顯示數據。
.TDBRadioGroup以單選框分組框的形式顯示數據。
.TDBLookupListBox以列表框的形式顯示這個表的Lookup表的數據。
.TDBLookupComboBox以組合框的形式顯示這個表的Lookup表的數據。
.TDBRichEdit以RTF格式顯示備註字段的內容。
.TDBCtrlGrid與TDBGrid相似,但每一個單元都可以分別設置屬性。
.TDBChart以圖表的形式顯示數據庫的數據,用法與TChart相似。
  上述數據控件在設計期具有數據感知的特點。如果正確設置了DataSource屬性指定了一個數據源,馬上就能看到數據,而不需要編譯和運行程序。
12.2 數據控件的基本用法
  這一節介紹數據控件的基本用法,包括怎樣指定一個數據源、怎樣編輯和更新數據、怎樣禁止和允許數據刷新。
12.2.1 指定一個數據源
  數據控件必須通過TDataSource構件連接數據集。TDataSource構件扮演的角色實際上就是數據控件與數據集之間的橋樑。
  首先,把一個數據集構件放到窗體或數據模塊上,設置它的DatabaseName屬性指定要訪問的數據庫,設置它的TableName屬性指定要訪問的表。
  接着,把一個TDataSource構件放到窗體或數據模塊上,設置它的DataSet屬性指定數據集。
  然後,把一個數據控件放到窗體上,設置它的DataSource屬性指定TDataSource構件,而這個TDataSource構件的DataSet屬性已經指定了一個數據集。
  最後,設置數據控件的DataField屬性指定要顯示的字段。不過,對於TDBGrid、TDBCtrlGrid和TDBNavigator構件來說,不需要設置DataField屬性,因爲這幾個控件是以整個數據集爲工作內容的。
12.2.2 編輯和更新數據
  除了TDBNavigator構件外,其他數據控件都是用來顯示和編輯數據的。這裏要介紹怎樣編輯數據。
  要使用戶能編輯數據,數據集必須進入dsEdit狀態。如果TDataSource的AutoEdit屬性設爲False,用戶不能直接編輯數據,除非程序調用Edit函數。
  要使用戶能夠在數據控件中修改數據,必須把數據控件的ReadOnly屬性設爲False。如果ReadOnly屬性設爲True,數據控件中顯示的數據就是隻讀的。
  一般情況下,TDataSource構件的Enabled屬性設爲True。如果這個屬性設爲False,數據控件就無法顯示數據,更不能修改數據。
  如果數據集構件的ReadOnly屬性設爲True,數據集就是隻讀的,用戶在數據控件中所作的修改不能寫到數據集中。
  除了TDBGrid構件外,當用戶修改了一個字段的值,還需要把輸入焦點移走,新的數據才寫到數據集中。在移走輸入焦點之前,用戶隨時可以按ESC鍵取消修改。
  在TDBGrid構件建立的柵格中,當用戶修改了一個字段的值,還需要把輸入焦點移到另一條記錄上,新的數據才寫到數據集中。
12.2.3 禁止和允許數據刷新
  當程序正在遍歷整個數據集或者搜索一個特定的記錄時,應當暫時禁止數據控件刷新數據,這樣能加快遍歷或搜索的速度,防止屏幕總是在閃爍。
  調用數據集的DisableControls可以暫時禁止連接這個數據集的數據控件刷新數據。DisableControls函數通常在循環操作前調用。等循環結束後,程序應當立即調用數據集構件的EnableControls函數重新允許刷新數據。
  爲了確保最後總是能恢復刷新,建議採用Try...Finally結構。這樣,即使在循環中出現異常,也可以保證總能調用EnableControls。
  下面的代碼演示了怎樣調用DisableControls和EnableControls函數:
CustTable.DisableControls;
Try
  CustTable.First;
  While not CustTable.EOF Do
  Begin
   ...
   CustTable.Next;
  End;
Finally
  CustTable.EnableControls;
End;
12.2.4 手動刷新數據
  調用數據集的Refresh可以讀取數據集中最新的數據並刷新數據控件,這個功能在多用戶環境尤其有用,因爲其他用戶有可能已改變了數據集中的數據。
  有時候,調用Refresh可能會導致意想不到的結果。例如,如果另一個用戶已經刪除了一條記錄,調用Refresh後,這條記錄將從數據控件中消失。
12.3 顯示單個字段的數據控件
  有的數據控件以數據庫的一個或幾個字段作爲工作內容,如TDBText和TDBEdit,而有的數據控件以整個數據集爲工作內容,如TDBGrid和TDBNavigator。
  顯示單個字段的數據控件往往是從一個標準的Windows控件演化而來的,例如,TDBEdit構件就可以認爲是TEdit的數據感知版本。
  圖12.1 用TDBText構件把數據作爲標籤顯示 
12.3.1 把數據作爲標籤顯示
  TDBText構件是一個只讀的數據控件,它非常類似於TLabel構件和TStaticText構件。TDBText構件能夠把數據作爲標籤顯示,用來標註其他控件。例如,可以用一個TDBText構件在魚的圖片下顯示魚的名稱(Common_Name字段),如圖12.1所示。
  TDBText構件需要指定一個字段。當用戶使用導航器或其他手段瀏覽記錄時,TDBText構件顯示的數據將自動變化,因爲TDBText構件總是顯示當前記錄的數據。例如,在圖12.1中,當用戶用鼠標單擊柵格的滾杆兩端的箭頭時,魚的圖片將自動變化,魚的名稱也相應改變,這一切都不需要編程。
  TDBText構件的AutoSize屬性一般要設爲True,這是因爲字段的內容長度可能是不同的。如果AutoSize屬性設爲False,有些較長的內容可能會被截斷。
12.3.2 顯示和編輯數據
  TDBText構件只能顯示數據,不能編輯數據。要既能顯示數據,又能編輯數據,就要用到TDBEdit構件。TDBEdit可以認爲是TEdit的數據感知(Data-Aware)版本。
  例如,有一個TDataSource構件叫CustomersSource,它的DataSet屬性指向一個TTable構件叫CustomersTable。把一個TDBEdit構件放在窗體上,其DataSource屬性設爲CustomersSource,把它的DataField屬性設爲CustNo。這個TDBEdit構件馬上就能顯示CustNo字段的值。用戶可以在編輯框中鍵入新的值。
12.3.3 顯示和編輯多行文本
  TDBMemo構件是TMemo構件的數據感知版本,可以顯示dBASE和Paradox數據庫中備註字段的內容。
  與TDBEdit不同的是,TDBMemo能夠以多行的形式顯示文本,同時也允許用戶鍵入多行文本。
  默認情況下,TDBMemo允許用戶修改它顯示的文本。如果不想讓用戶修改文本,只要把ReadOnly屬性設爲True即可。要允許用戶在文本中插入一個製表符,應當把WantTabs屬性設爲True,否則,當用戶按下Tab鍵,將把輸入焦點移走,而不是插入製表符。
  要限制用戶最多可輸入的字符數,可以設置MaxLength屬性。如果這個屬性設爲0,表示沒有限制。
  此外,ScrollBars屬性可以設置要不要加上滾動欄,WordWrap屬性可以設置是否允許自動繞回,Alignment屬性可以設置文本的對齊方式。
  在運行期,您可以調用CutToClipboard和CopyToClipboard函數把選擇的文本剪切和複製到剪貼板中,調用PasteFromClipboard能夠粘貼剪貼板中的文本。如果AutoDisplay屬性設爲True,當DataField屬性所指定的字段的內容改變了時,TDBMemo構件會自動刷新。如果AutoDisplay屬性設爲False,TDBMemo 構件上只顯示字段名,用戶必須雙擊這個構件或程序調用LoadMemo才能刷新數據。
12.3.4 以RTF格式顯示文本
  TDBRichEdit構件可以認爲是TRichEdit構件的數據感知版本,用於以RTF格式顯示BLOB字段中的格式化文本。它的用法類似於TDBMemo構件,也能顯示多行文本。
  注意:儘管TDBRichEdit構件能夠顯示RTF格式的文本,並且提供了很強的編輯功能,但是,它本身並沒有提供用戶界面,應用程序必須設計出相應的用戶界面,才能把TDBRichEdit 構件強大的功能發揮出來。
  默認情況下,TDBRichEdit構件允許用戶鍵入新的文本。如果不想讓用戶修改文本,可以把ReadOnly屬性設爲True。
  要允許用戶在文本中插入一個製表符,應當把WantTabs屬性設爲True,否則,當用戶按下Tab鍵,將把輸入焦點移走,而不是插入製表符。
  要限制用戶最多可輸入的字符數,可以設置MaxLength屬性。如果這個屬性設爲0,表示沒有限制。
  如果AutoDisplay屬性設爲True,當DataField屬性所指定的字段的內容改變了時,TDBRichEdit構件會自動刷新。如果AutoDisplay屬性設爲False,TDBRichEdit構件上只顯示字段名,用戶必須雙擊這個構件或程序調用LoadMemo函數才能刷新數據。
12.3.5 顯示和編輯圖像
  TDBImage構件可以認爲是TImage構件的數據感知版本,它可以顯示BLOB字段的內容。TDBImage構件從數據集中檢索了圖像後,在本地以DIB格式建立一個副本。
  可以調用CutToClipboard或CopyToClipboard函數把圖像剪切或複製到剪貼板中,調用 PasteFromClipboard可以從剪貼板中粘貼圖像。
  如果Stretch屬性設爲True,圖像將自動縮放,以適應TDBImage構件的大小,這樣就可能造成圖像變形。如果AutoDisplay屬性設爲True,當DataField屬性所指定的字段的內容改變了時,TDBImage構件會自動刷新。如果這個屬性設爲False,TDBImage構件上只顯示字段名,用戶必須雙擊這個構件才能刷新數據,當然也可以調用LoadPicture來刷新數據。
12.4 用列表框和組合框顯示和編輯數據
  有4個特殊的數據控件可以用列表框和組合框顯示和編輯數據,它們可以認爲是標準的列表框和組合框的數據感知版本。下面簡單介紹這4個數據控件:
.TDBListBox用列表框顯示一組數據,讓用戶從中選擇一個值。
.TDBComboBox用組合框顯示一組數據,讓用戶從中選擇一個值。
.TDBLookupListBox用列表框顯示另一個數據集中的一組數據,讓用戶從中選擇一個值。
.TDBLookupComboBox用組合框顯示另一個數據集中的一組數據,讓用戶從中選擇一個值。
12.4.1 TDBListBox
  TDBListBox構件能夠用列表框顯示一組數據,用戶可以從中選擇一個數據。當用戶瀏覽記錄時,程序將自動在列表框中搜索與字段的值匹配的項,如果找到就選擇這一項,如圖12.2所示。
  在列表框中選擇匹配的項反過來,當用戶在列表框中選擇了某個項,程序就自動把當前記錄的該字段的值改爲列表框中選擇的值。當然,要使修改有效還必須調用Post函數。
  要在設計期設置列表框中顯示的項,可以單擊Items屬性邊上的省略號按鈕打開一個字符串列表編輯器,然後輸入一些字符串。
  如果IntegralHeight屬性設爲True,列表框的高度將總是項的高度的整數倍。
12.4.2 TDBComboBox
  TDBComboBox構件實際上是TComboBox構件的數據感知版本,它能以組合框的形式顯示一組數據,讓用戶從列表中選擇一個值或直接輸入一個值。
  Items屬性用於設置列表中要顯示的一組數據。在設計期,可以單擊Items屬性邊上的省略號按鈕打開一個字符串列表編輯器,然後輸入一些字符串。
  DropDownCount屬性用於設置當用戶下拉組合框時不需要加滾動欄就能顯示的項的個數,默認是8,表示用戶下拉組合框時如果項的個數超過8個才加上滾動欄。如果實際的項數還沒有DropDownCount屬性指定的值多,下拉的組合框的高度自動縮小。
  在Style屬性設爲csOwnerDrawFixed的情況下,ItemHeight屬性用於設置項的高度。
12.4.3 顯示另一個數據集中的數據
  TDBLookupListBox構件和TDBLookupComboBox構件分別以列表框和組合框的形式顯示另一個數據集中的數據。
  假設有一個表格叫OrdersTable,其中包含一個CustNo字段,用於表達客戶的編號,但OrdersTable表中除了客戶的編號外,不包含客戶的其他信息。而另一個表格假設叫CustomersTable,除了有CustNo字段外,還有諸如客戶的公司名稱、地址等信息。
  TDBLookupListBox構件可以實現這樣的功能,當用戶在OrdersTable中瀏覽記錄時,程序首先在CustomersTable中查找與CustNo字段匹配的記錄,如果找不到,就從列表中查找與Company字段匹配的字符串;如果找到,就選擇這一項,如圖12.3所示。 
  圖12.3 TDBLookupListBox構件的用法
  當用戶在列表中選擇了一項,程序就在CustomersTable中查找與字符串匹配的Company字段,如果找到,就用CustNo字段的值替換OrdersTable表中的CustNo字段。
12.5 用複選框處理布爾類型的字段
   TDBCheckBox構件可以認爲是TCheckBox構件的數據感知版本,用於處理布爾類型的字段。例如,可以用一個複選框來表示客戶是否已付帳。
   TDBCheckBox構件實際上是把字段的值與預設的兩個字符串比較,這兩個字符串分別由ValueChecked和ValueUnChecked屬性指定。如果字段的值與ValueChecked屬性指定的字符串匹配,就選中複選框。如果字段的值與ValueUnchecked屬性指定的字符串匹配,就不選中複選框。注意:ValueChecked屬性和ValueUnchecked屬性所指定的字符串不能相同。
  一般情況下,ValueChecked屬性設爲“True”、“Yes”之類的字符串,但也可以是其他任意的字符串,甚至是一組字符串,彼此之間要用分號隔開,例如:
  DBCheckBox1.ValueChecked := True;Yes;On;
  上述情況下,當字段的值只要與其中一個字符串匹配,就選中複選框。要說明的是,ValueChecked屬性指定的字符串是大小寫敏感的。
  一般情況下,ValueUnchecked屬性設爲“False”、“No”之類的字符串,但也可以是其他任意的字符串,甚至是一組字符串,彼此之間用分號隔開。
  如果字段的值既不與ValueChecked屬性指定的字符串匹配,也不與ValueUnchecked屬性指定的字符串匹配,複選框就變灰。
12.6 用單選分組框限制字段的值
   TDBRadioGroup構件可以認爲是TRadioGroup構件的數據感知版本,它可以限制用戶從一組數據中選擇字段的值。
   與TRadioGroup構件一樣,首先要設置Items屬性指定單選分組框中要顯示哪些項。Items屬性是一個典型的TStrings對象,每一個字符串對應着單選分組框中的一個按鈕。
  當用戶瀏覽記錄時,如果字段的值與單選分組框中的某個按鈕的標籤匹配,就選擇這個按鈕,如圖12.4所示。 
  圖12.4 選擇與CustNo字段的值匹配的單選框
  反過來,當用戶在單選分組框中選擇一個按鈕,程序就用這個按鈕的標籤賦值給DataField屬性指定的字段。
  如果不想使按鈕的標籤與字段的值匹配,可以另外指定其他字符串,這就要用到Values屬性。Values屬性也是一個TStrings對象,用於指定一組字符串。當用戶在單選分組框中選擇一個按鈕,程序就用Values屬性中的一個字符串賦值給DataField屬性指定的字段,而不是按鈕的標籤。
12.7 使用TDBGridTDBGrid構件
  以柵格的形式顯示和編輯數據集中的數據。它的外觀很大程度上取決於下面三個因素:
.一是永久的列對象。
.二是永久的字段對象。
.三是數據集構件的ObjectView屬性將影響ADT和數組字段的顯示方式。
  對於TDBGrid構件來說,最重要的屬性是Columns,這是一個TDBGridColumns對象,用於管理一組TColumn對象。在設計期,可以打開一個編輯器建立永久的列對象,然後在對象觀察器中設置列對象的屬性。
12.7.1動態的列對象
  如果TDBGridColumns的State屬性設爲csDefault,列是動態生成的,列的屬性取決於字段的屬性。當字段的屬性發生變化時,列的屬性也跟着變化。
  讓列動態生成的好處是,可以在運行期動態地選擇其他數據集,而不用擔心柵格是否適合於顯示新的數據集。例如,可以用同一個TDBGrid構件先顯示一個Paradox表,再顯示查詢另一個數據庫的結果。
  在設計期,無法直接修改動態列對象的屬性,只能修改字段對象的屬性,從而間接地修改動態列對象的屬性。 
  動態列對象的生存期也取決於字段對象的生存期。如果數據集沒有建立永久的字段對象,那麼,當數據集關閉時,所有的動態列對象也將消失。
  注意:如果在運行期把TDBGridColumns的State屬性設爲csDefault,將刪除所有的列對象,然後根據數據集中的字段對象重建列對象。
12.7.2 永久的列對象
  要能夠在設計期自定義柵格,就要用到永久的列對象。建立了永久的列對象後,如果TDBGridColumns的State屬性設爲csCustomized,就可以獨立設置每一列的屬性。例如,默認情況下,列的標題顯示字段的標籤即DisplayLabel屬性,通過修改TColumnTitle的Caption屬性可以重新指定列的標題,而TField的DisplayLabel屬性則不會受到影響。
  TDBGridColumns的State屬性設爲csCustomized適合於那些數據集的結構是固定不變的情況。如果需要在運行期切換不同的數據集,就不能把State屬性設爲csCustomized。
  要創建永久的列對象,首先要在窗體上選擇TDBGrid構件,然後對象觀察器中單擊Columns屬性邊上的省略號按鈕將打開如圖12.5所示的編輯器。
  圖12.5 創建永久的列對象
  剛開始的時候,這個編輯器是空白的,這是因爲,默認情況下,柵格中的列對象都是動態生成的,還沒有永久的列對象。
  要基於數據集中的每一個字段分別創建一個永久的列對象,可以單擊鼠標右鍵,在彈出的菜單中選擇“Add All Fields”命令。
  要創建一個獨立的永久列對象,可以單擊工具欄上的(Add New)按鈕。選擇這個剛創建的列對象,然後在對象觀察器中設置FieldName屬性指定一個字段,設置Caption屬性指定列的標題。
  要刪除一個列對象,可以單擊工具欄上的(Delete Selected)按鈕。如果把永久的列都刪掉,柵格反而能顯示數據集中所有的字段,這是因爲,永久的列刪掉以後,Delphi 4會自動把TDBGridColumns的State屬性設爲csDefault並且動態生成所有的列。  要調整列在柵格中顯示的順序,可以用鼠標把列對象前移或後移。
  對於永久的列對象來說,它的屬性的默認值仍然取自於字段,除非您修改了永久列對象的屬性。例如,默認的情況下,列的標題就是字段的DisplayLabel屬性。如果修改字段的DisplayLabel屬性,列的標題將隨之改變。但是,一旦您修改了列對象的Caption屬性,列的標題不再與字段的DisplayLabel屬性存在聯動關係,它們彼此是獨立的。
  前面講過,創建一個永久的列對象時,需要設置FieldName屬性指定一個字段。不過,您也可以讓FieldName屬性爲空,此時,TColumn對象的Field屬性將返回NULL,並且該列在柵格中是空白的。空白的列往往用於用戶顯示一些自定義的內容,如圖像或圖表等。
  幾個列對象的FieldName屬性可以設爲同一個字段。由此可見,TDBGrid的FieldCount屬性可能小於柵格的列數
12.7.3 讓用戶編輯數據
  對於永久的列對象來說,可以提供幾種方式讓用戶編輯數據。一是以組合框的方式顯示另一個數據集的數據,二是建立一個靜態的列表,三是用省略號按鈕打開一個對話框。
  要以組合框的方式顯示另一個數據集的數據,首先必須在數據集中增加一個Lookup字段,然後創建一個永久的列對象,設置它的FieldName屬性指定這個Lookup字段,並且把它的ButtonStyle屬性設爲cbsAuto。經過上述操作後,柵格的效果如圖12.6所示。
  圖12.6 以組合框的形式顯示另一個數據集的數據
  要建立一個靜態的列表,不必事先增加一個Lookup字段,只要先創建一個永久的列對象,把ButtonStyle屬性設爲cbsAuto,在對象觀察器中單擊Picklist屬性邊上的省略號按鈕打開一個字符串列表編輯器,然後依次鍵入一些字符串。
  要用一個對話框讓用戶選擇數據,必須把列對象的ButtonStyle屬性設爲cbsEllipsis。當程序運行時,該列將出現一個省略號按鈕,單擊這個省略號按鈕將觸發OnEditButtonClick事件,在處理這個事件的句柄中可以打開一個對話框,讓用戶選擇數據。對於圖像字段來說,當用戶單擊省略號按鈕時,可以顯示一個圖像。
12.7.4 在設計期設置列對象的屬性
  列對象的屬性決定了數據在柵格中的顯示方式。在設計期,可以設置它的下列屬性:
.Alignment用於設置數據的對齊方式,默認值是TField的Alignment。
.ButtonStyle設爲cbsAuto表示加上一個組合框。設爲cbsEllipsis表示加上一個省略號按鈕,當用戶單擊此按鈕將觸發OnEditButtonClick。設爲cbsNone表示既沒有組合框也沒有省略號按鈕。
.Color用於設置背景顏色,默認值是TDBGrid的Color。
.DropDownRows 下拉列表框中的項數,默認值是7。
.Expanded如果列對象所對應的字段是ADT或數組字段,這個屬性用於控制是否展開。l FieldName用於指定一個字段,可以讓它空着。
.ReadOnly設爲True表示該列是隻讀的,不能編輯。
.Width用於設置列的寬度,默認值是TField的DisplayWidth。
.Font用於設置該列中字符的字體,默認值是TDBGrid的Font。
.PickList用於建立一個靜態的列表。
.Title這是個TColumnTitle對象,用於設置列的標題。
  其中,TColumnTitle具有下列屬性:
.Alignment用於設置標題的對齊方式,設爲taLeftJustify表示左對齊,設爲taCenter表示居中,設爲taRightJustify表示右對齊。
.Caption用於指定標題的文字,默認值是TField的DisplayLabel。
.Color用於設置標題的背景顏色,默認值是TDBGrid的FixedColor。
.Font用於設置標題的字體,默認值是TDBGrid的TitleFont。
12.7.5 顯示ADT和數組字段的值
  Delphi 4的TDBGrid構件完全支持Oracle 8的對象字段。
  如果數據集構件的ObjectView屬性設爲True,對象字段就可以展開或摺疊。當對象字段展開的時候,原來的一列就分爲若干列,每一列顯示一個子字段的值,每一個子字段所在的列都有自己的標題欄,這樣可以明顯地看出字段之間的包含關係。當對象字段摺疊的時候,就只顯示一個字符串,該字符串列出了每個子字段的值,彼此之間用逗號隔開。
  如果數據集構件的ObjectView屬性設爲False,每個子字段與對象字段一樣,都單獨佔一列。
  下面介紹幾個與對象字段有關的屬性。一是TColumn的Expandable屬性,如果設爲True,表示該列是可展開的。二是TColumn的Expanded屬性,用於測試列當前是否已展開。三是TDBGrid的MaxTitleRows屬性,用於設置柵格中最多可出現幾行標題。四是TDataSet的ObjectView,這個屬性前面已介紹過了。五是TColumn的ParentColumn屬性,用於返回顯示父字段的列對象。
   圖12.7演示了ObjectView屬性設爲False的情況:
   圖12.7 ObjectView屬性設爲False的情況
   圖12.8演示了ObjectView屬性設爲True但對象字段被摺疊的情況:
   圖12.8 ObjectView屬性設爲True但對象字段被摺疊的情況
   圖12.Array演示了ObjectView屬性設爲True但對象字段被展開的情況:
   圖12.Array ObjectView屬性設爲True但對象字段被展開的情況
12.7.6 設置柵格的選項
  可以在設計期設置柵格的選項,這就要用到TDBGrid構件的Options屬性。Options屬性是一個集合,可以包含下列元素:
.dgEditing如果包含這個元素(下同),允許用戶修改柵格中的數據;
.dgAlwaysShowEditor柵格自動處於編輯狀態,否則需按F2才進入編輯狀態;
.dgTitles顯示列的標題;
.dgIndicator當前行的最左端將顯示一個4符號;
.dgColumnResize列的寬度可以重設;
.dgColLines列與列之間用線分開; 
.dgRowLines行與行之間用線分開;
.dgTabs可以用Tab鍵和Shift+Tab鍵在列與列之間移動輸入焦點;
.dgRowSelect用戶可以選擇一整行,否則就只能選擇一個單元;
.dgAlwaysShowSelection即使輸入焦點移走,選擇的單元仍然保持選擇狀態;
.dgConfirmDelete按Ctrl+Delete刪除一行時將顯示一個確認框,讓用戶確認;
.dgCancelOnExit在柵格退出的時候,任何未決的修改將被取消
.dgMultiSelect用戶可以在柵格中選擇多行,相當於一個複選的列表框。
12.7.7 在運行期響應用戶的動作
  TDBGrid構件具有幾個事件,用於響應用戶的動作。由於柵格是由行和列構成的,因此,在事件句柄中,首先要區分當前是在哪一列上。下面列出了這些事件:
.OnCellClick當用戶單擊一個單元時將觸發這個事件。
.OnColEnter當輸入焦點進入某一列時將觸發這個事件。
.OnColExit當輸入焦點離開某一列時將觸發這個事件。
.OnColumnMoved當用戶把某一列移到另一個位置時將觸發這個事件。
.OnDblClick當用戶在柵格中雙擊時將觸發這個事件。
.OnDragDrop當用戶在柵格中釋放被拖曳的對象時將觸發這個事件。
.OnDragOver當用戶拖着一個對象經過柵格時將觸發這個事件。
.OnDrawColumnCell當某個單元需要重畫時將觸發這個事件。
.OnDrawDataCell 在State屬性設爲csDefault的情況下,當某個單元需要重畫時將觸發這個事件。
.OnEditButtonClick當用戶單擊省略號按鈕時將觸發這個事件。
.OnEndDrag當用戶釋放了鼠標時將觸發這個事件。
.OnEnter當柵格得到輸入焦點時將觸發這個事件。
.OnExit當柵格失去輸入焦點時將觸發這個事件。
.OnKeyDown當用戶按下一個鍵時將觸發這個事件。
.OnKeyPress當用戶按下一個可見的字符鍵時將觸發這個事件。
.OnKeyUp當用戶釋放一個鍵時將觸發這個事件。
.OnStartDrag當用戶開始進行拖放操作時將觸發這個事件。
.OnTitleClick當用戶單擊某一列的標題時將觸發這個事件。
12.7.8 一個特殊的數據庫柵格
  TDBGrid構件的特點是一行只顯示一個記錄,但可以設置每一列的屬性。 TDBCtrlGrid構件的特點是每一行都是一個窗格(TPanel對象),可以在窗格上放一些控件。例如,可以把一個TDBEdit構件放到窗格上,讓它顯示某個字段的值,還可以在編輯框的旁邊加一個TLabel構件作爲標籤。TDBCtrlGrid的另一個特點是一行上可以有多個窗格,也就是說,一行可以顯示多個記錄,窗格的高度和寬度都是可以調整的。
  首先,要把一個TDBCtrlGrid構件放到窗體上,設置它的DataSource屬性指定一個TDataSource構件。剛開始的時候,TDBCtrlGrid構件有三行和一列。
  接着,要把一些數據控件放到TDBCtrlGrid構件的“設計單元”上,設置這些數據控件的DataField屬性指定要顯示的字段。
  “設計單元”通常是最上邊或最左邊的那個單元,與其他單元在外觀上的區別是它沒有斜線底紋。
  注意:只能把數據控件放到TDBCtrlGrid構件的“設計單元”上,當程序編譯運行後,會自動把“設計單元”上的數據控件複製到其他單元,每個單元顯示不同的記錄。
  圖12.10演示了TDBCtrlGrid構件的用法: 
  圖12.10 TDBCtrlGrid構件的用法
  下面列出了TDBCtrlGrid構件的屬性:
.AllowDelete設爲True表示允許刪除記錄。
.AllowInsert設爲True表示允許插入記錄。
.ColCount用於設置每一行的窗格數,默認是1。
.Orientation設爲goVertical表示從上到下顯示記錄,設爲goHorizontal表示從左到右顯示記錄。 
.PanelHeight用於設置窗格的高度,默認是72。
.PanelWidth用於設置窗格的寬度,默認是200。
.RowCount用於設置行數,默認是3。
.ShowFocus如果設爲True,顯示當前記錄的窗格上有一個虛線邊框。
.SelectedColor用於設置顯示當前記錄的窗格的背景顏色。
12.8 導 航 器
  導航器是用TDBNavigator構件實現的,它可以讓用戶方便地瀏覽和操縱記錄。導航器最多可由10個按鈕組成,包括:
.First第一個記錄;
.Prior前一個記錄;
.Next後一個記錄;
.Last最後一個記錄;
.Insert插入一個空白的記錄;
.Delete刪除當前記錄;
.Edit允許編輯當前記錄;
.Post使未決的編輯操作有效;
.Cancel取消未決的編輯操作;
.Refresh用數據集中的最新的數據刷新記錄。
  可以根據需要,在導航器上有選擇地顯示部分按鈕,這就要用到VisibleButtons屬性。
  在設計期,可以在對象觀察器中選擇要顯示在導航器上的按鈕。在運行期,您可以通過編程選擇要顯示在導航器上的按鈕。例如,假設要用同一個導航器爲兩個數據集導航,其中一個允許用戶編輯數據,另一個不允許用戶編輯數據。當在兩個數據集之間切換時,應當動態地改變導航器上的按鈕,因爲對於不允許用戶編輯數據的數據集來說,導航器上不應當出現Insert、Delete、Edit、Post、Cancel和Refresh等按鈕。下面代碼把這些按鈕隱藏:
Procedure TForm1.CustomerCompanyEnter(Sender :TObject);
Begin
If Sender = CustomerCompany then
Begin
DBNavigatorAll.DataSource := CustomerCompany.DataSource;
DBNavigatorAll.VisibleButtons := [nbFirst,nbPrior,nbNext,nbLast];
End
Else
Begin
DBNavigatorAll.DataSource := OrderNum.DataSource;
DBNavigatorAll.VisibleButtons := DBNavigatorAll.VisibleButtons + [nbInsert,nbDelete,nbEdit,nbPost,nbCancel,nbRefresh]; 
End;
End;
  這裏順便說一下,當同一個導航器需要爲幾個數據集導航時,就要動態地設置DataSource屬性。假設窗體上有兩個TDataSource構件,分別叫CustomersSource和OrdersSource,它們的DataSet屬性分別指定CustomersTable表和OrdersTable表,另外,窗體上有兩個TDBEdit構件,分別叫CustomersEdit和OrdersEdit,它們的DataSource屬性分別指向CustomersSource和OrdersSource。下面這段程序爲這兩個TDBEdit構件寫了一個公共的事件句柄來處理OnEnter事件,當用戶在CustomersEdit 上編輯時,導航器將爲CustomersTable導航,當用戶在OrdersEdit上編輯時,導航器將爲OrdersTable導航。
Procedure TForm1. CustomerEditEnter(Sender: TObject);
Begin
If Sender = CustomerEdit Then
   DBNavigatorl.DataSource := CustomerEdit.DataSource;
Else
DBNavigator1.DataSource := OrderEdit.DataSource;
End;
12.Array 數 據 源
  TDataSource構件是一個非可視的構件,它充當了數據集和數據控件之間的橋樑。每一個數據控件都必須指定一個數據源(TDataSource構件),相應地,TDataSource構件的DataSet屬性必須指定一個數據集。下面簡單介紹一下TDataSource構件的屬性和事件。
  DataSet屬性用於指定一個數據集。在設計期,可以在對象觀察器中爲DataSet屬性選擇一個數據集。在運行期,可以通過代碼動態地選擇數據集。程序示例如下:
With CustSource Do
Begin
If DataSet = Customers then
DataSet := Orders
Else
DataSet := Customers;
End;
  也可以指定另一個窗體上的數據集構件,例如:
Procedure TForm2. FormCreate (Sender : TObject);
Begin
DataSource1.Dataset := Form1.Table1;
End;
  一般情況下,TDataSource構件的名稱是無關緊要的。不過,TDataSource構件的名稱應當能反映它所連接的數據集,例如,假設TDataSource構件連接的數據集叫Customers,相應地,TDataSource構件的名稱最好叫CustomersSource。 
  Enabled屬性用於控制TDataSource構件是否與數據集連接,設爲True表示連接,設爲False表示暫時斷開連接。如果Enabled屬性設爲False,凡是連接於這個數據源的數據控件將變成空白。
  如果AutoEdit屬性設爲True,當用戶在數據控件中鍵入字符時,數據集就自動進入dsEdit狀態。如果AutoEdit屬性設爲False,程序必須調用Edit函數才能進入dsEdit狀態。
  當數據集的當前記錄的位置發生變化時將觸發OnDataChange事件,這可能是因爲程序調用了Next、Previous、Insert等方法。
  當前記錄的數據將要被更新時將觸發OnUpdateData事件,這可能是因爲調用了Post。在處理這個事件的句柄中,可以對數據進行校驗。
  當State屬性發生變化時將觸發OnStateChange事件。例如,可以用一個標籤動態地顯示當前的狀態。程序示例如下:
ProcedureTForm1.DataSource1.StateChange(Sender:TObject);
var
S:String;
Begin
Case CustTable.State of
dsInactive: S := Inactive;
dsBrowse: S := Browse;
dsEdit: S := Edit;
dsInsert: S := Insert;
dsSetKey: S := SetKey;
End; 
CustTableStateLabel.Caption := S;
End;
  利用OnStateChange事件也可以動態地允許或禁止按鈕和菜單項,程序示例如下:
Procedure Form1.DataSource1.StateChange(Sender: TObject);
Begin
CustTableEditBtn.Enabled := (CustTable.State = dsBrowse);
CustTableCancelBtn.Enabled := CustTable.State in [dsInsert, dsEdit, dsSetKey];
...
End;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章