数据库控件使用入门
在数据库应用程序中,数据控件是经常要用到的。数据控件都是可视的。也就是说,如果修改了这些构件的属性,能在窗体上马上反映出来。如果这些构件的Enabled属性设为True并且数据集的Active属性也设为True,在设计期就可以看到数据。下面就来介绍一下这些控件的简单应用:
指定一个数据源
数据控件必须通过TDataSource构件连接数据集。TDataSource构件扮演的角色实际上就是数据控件与数据集之间的桥梁。首先,把一个数据集构件放到窗体或数据模块上,设置它的DatabaseName属性指定要访问的数据库,设置它的TableName属性指定要访问的表。接着,把一个TDataSource构件放到窗体或数据模块上,设置它的DataSet属性指定数据集。然后,把一个数据控件放到窗体上,设置它的DataSource属性指定TDataSource构件,而这个TDataSource构件的DataSet属性已经指定了一个数据集。最后,设置数据控件的DataField属性指定要显示的字段。不过,对于TDBGrid、TDBCtrlGrid和TDBNavigator构件来说,不需要设置DataField属性,因为这几个控件是以整个数据集为工作内容的。
编辑和更新数据
除了TDBNavigator构件外,其他数据控件都是用来显示和编辑数据的。这里要介绍怎样编辑数据。
要使用户能编辑数据,数据集必须进入dsEdit状态。如果TDataSource的AutoEdit属性设为False,用户不能直接编辑数据,除非程序调用Edit函数。
要使用户能够在数据控件中修改数据,必须把数据控件的ReadOnly属性设为False。如果ReadOnly属性设为True,数据控件中显示的数据就是只读的。一般情况下,TDataSource构件的Enabled属性设为True。如果这个属性设为False,数据控件就无法显示数据,更不能修改数据。
如果数据集构件的ReadOnly属性设为True,数据集就是只读的,用户在数据控件中所作的修改不能写到数据集中。除了TDBGrid构件外,当用户修改了一个字段的值,还需要把输入焦点移走,新的数据才写到数据集中。在移走输入焦点之前,用户随时可以按ESC键取消修改。在TDBGrid构件建立的栅格中,当用户修改了一个字段的值,还需要把输入焦点移到另一条记录上,新的数据才写到数据集中。
禁止和允许数据刷新
当程序正在遍历整个数据集或者搜索一个特定的记录时,应当暂时禁止数据控件刷新数据,这样能加快遍历或搜索的速度,防止屏幕总是在闪烁。调用数据集的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;
手动刷新数据
调用数据集的Refresh可以读取数据集中最新的数据并刷新数据控件,这个功能在多用户环境尤其有用,因为其他用户有可能已改变了数据集中的数据。有时候,调用Refresh可能会导致意想不到的结果。例如,如果另一个用户已经删除了一条记录,调用Refresh后,这条记录将从数据控件中消失。
显示单个字段的数据控件
有的数据控件以数据库的一个或几个字段作为工作内容,如TDBText和TDBEdit,而有的数据控件以整个数据集为工作内容,如TDBGrid和TDBNavigator。显示单个字段的数据控件往往是从一个标准的Windows控件演化而来的,例如,TDBEdit构件就可以认为是TEdit的数据感知版本。
1、把数据作为标签显示
TDBText构件是一个只读的数据控件,它非常类似于TLabel构件和TStaticText构件。TDBText构件能够把数据作为标签显示,用来标注其他控件。例如,可以用一个TDBText构件显示名称(Common_Name字段)。
TDBText构件需要指定一个字段。当用户使用导航器或其他手段浏览记录时,TDBText构件显示的数据将自动变化,因为TDBText构件总是显示当前记录的数据。
TDBText构件的AutoSize属性一般要设为True,这是因为字段的内容长度可能是不同的。如果AutoSize属性设为False,有些较长的内容可能会被截断。
2、显示和编辑数据
TDBText构件只能显示数据,不能编辑数据。要既能显示数据,又能编辑数据,就要用到TDBEdit构件。TDBEdit可以认为是TEdit的数据感知(Data-Aware)版本。例如,有一个TDataSource构件叫CustomersSource,它的DataSet属性指向一个TTable构件叫CustomersTable。把一个TDBEdit构件放在窗体上,其DataSource属性设为CustomersSource,把它的DataField属性设为CustNo。这个TDBEdit构件马上就能显示CustNo字段的值。用户可以在编辑框中键入新的值。
显示和编辑多行文本
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才能刷新数据。
以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函数才能刷新数据。
显示和编辑图像
TDBImage构件可以认为是TImage构件的数据感知版本,它可以显示BLOB字段的内容。TDBImage构件从数据集中检索了图像后,在本地以DIB格式建立一个副本。
可以调用CutToClipboard或CopyToClipboard函数把图像剪切或复制到剪贴板中,调用 PasteFromClipboard可以从剪贴板中粘贴图像。
如果Stretch属性设为True,图像将自动缩放,以适应TDBImage构件的大小,这样就可能造成图像变形。
如果AutoDisplay属性设为True,当DataField属性所指定的字段的内容改变了时,TDBImage构件会自动刷新。如果这个属性设为False,TDBImage构件上只显示字段名,用户必须双击这个构件才能刷新数据,当然也可以调用LoadPicture来刷新数据。
用列表框和组合框显示和编辑数据
有4个特殊的数据控件可以用列表框和组合框显示和编辑数据,它们可以认为是标准的列表框和组合框的数据感知版本。下面简单介绍这4个数据控件:
1、TDBListBox用列表框显示一组数据,让用户从中选择一个值。
2、TDBComboBox用组合框显示一组数据,让用户从中选择一个值。
3、TDBLookupListBox用列表框显示另一个数据集中的一组数据,让用户从中选择一个值。
4、TDBLookupComboBox用组合框显示另一个数据集中的一组数据,让用户从中选择一个值。
TDBComboBox
TDBComboBox构件实际上是TComboBox构件的数据感知版本,它能以组合框的形式显示一组数据,让用户从列表中选择一个值或直接输入一个值。
Items属性用于设置列表中要显示的一组数据。在设计期,可以单击Items属性边上的省略号按钮打开一个字符串列表编辑器,然后输入一些字符串。
DropDownCount属性用于设置当用户下拉组合框时不需要加滚动栏就能显示的项的个数,默认是8,表示用户下拉组合框时如果项的个数超过8个才加上滚动栏。如果实际的项数还没有DropDownCount属性指定的值多,下拉的组合框的高度自动缩小。
在Style属性设为csOwnerDrawFixed的情况下,ItemHeight属性用于设置项的高度。
显示另一个数据集中的数据
TDBLookupListBox构件和TDBLookupComboBox构件分别以列表框和组合框的形式显示另一个数据集中的数据。
假设有一个表格叫OrdersTable,其中包含一个CustNo字段,用于表达客户的编号,但OrdersTable表中除了客户的编号外,不包含客户的其他信息。而另一个表格假设叫CustomersTable,除了有CustNo字段外,还有诸如客户的公司名称、地址等信息。
TDBLookupListBox构件可以实现这样的功能,当用户在OrdersTable中浏览记录时,程序首先在CustomersTable中查找与CustNo字段匹配的记录,如果找不到,就从列表中查找与Company字段匹配的字符串;如果找到,就选择这一项。
用复选框处理布尔类型的字段
TDBCheckBox构件可以认为是TCheckBox构件的数据感知版本,用于处理布尔类型的字段。例如,可以用一个复选框来表示客户是否已付帐。
TDBCheckBox构件实际上是把字段的值与预设的两个字符串比较,这两个字符串分别由ValueChecked和ValueUnChecked属性指定。如果字段的值与ValueChecked属性指定的字符串匹配,就选中复选框。如果字段的值与ValueUnchecked属性指定的字符串匹配,就不选中复选框。注意:ValueChecked属性和ValueUnchecked属性所指定的字符串不能相同。
一般情况下,ValueChecked属性设为“True”、“Yes”之类的字符串,但也可以是其他任意的字符串,甚至是一组字符串,彼此之间要用分号隔开,例如:
DBCheckBox1.ValueChecked := 'True;Yes;On';
上述情况下,当字段的值只要与其中一个字符串匹配,就选中复选框。要说明的是,ValueChecked属性指定的字符串是大小写敏感的。一般情况下,ValueUnchecked属性设为“False”、“No”之类的字符串,但也可以是其他任意的字符串,甚至是一组字符串,彼此之间用分号隔开。如果字段的值既不与ValueChecked属性指定的字符串匹配,也不与ValueUnchecked属性指定的字符串匹配,复选框就变灰。
使用TDBGrid
TDBGrid构件以栅格的形式显示和编辑数据集中的数据。它的外观很大程度上取决于下面三个因素:l 一是永久的列对象。 二是永久的字段对象。 三是数据集构件的ObjectView属性将影响ADT和数组字段的显示方式。对于TDBGrid构件来说,最重要的属性是Columns,这是一个TDBGridColumns对象,用于管理一组TColumn对象。在设计期,可以打开一个编辑器建立永久的列对象,然后在对象观察器中设置列对象的属性。
动态的列对象
如果TDBGridColumns的State属性设为csDefault,列是动态生成的,列的属性取决于字段的属性。当字段的属性发生变化时,列的属性也跟着变化。让列动态生成的好处是,可以在运行期动态地选择其他数据集,而不用担心栅格是否适合于显示新的数据集。例如,可以用同一个TDBGrid构件先显示一个Paradox表,再显示查询另一个数据库的结果。在设计期,无法直接修改动态列对象的属性,只能修改字段对象的属性,从而间接地修改动态列对象的属性。
动态列对象的生存期也取决于字段对象的生存期。如果数据集没有建立永久的字段对象,那么,当数据集关闭时,所有的动态列对象也将消失。注意:如果在运行期把TDBGridColumns的State属性设为csDefault,将删除所有的列对象,然后根据数据集中的字段对象重建列对象。
要能够在设计期自定义栅格,就要用到永久的列对象。建立了永久的列对象后,如果TDBGridColumns的State属性设为csCustomized,就可以独立设置每一列的属性。例如,默认情况下,列的标题显示字段的标签即DisplayLabel属性,通过修改TColumnTitle的Caption属性可以重新指定列的标题,而TField的DisplayLabel属性则不会受到影响。TDBGridColumns的State属性设为csCustomized适合于那些数据集的结构是固定不变的情况。如果需要在运行期切换不同的数据集,就不能把State属性设为csCustomized。要创建永久的列对象,首先要在窗体上选择TDBGrid构件,然后对象观察器中单击Columns属性边上的省略号按钮将打开编辑器。
刚开始的时候,这个编辑器是空白的,这是因为,默认情况下,栅格中的列对象都是动态生成的,还没有永久的列对象。要基于数据集中的每一个字段分别创建一个永久的列对象,可以单击鼠标右键,在弹出的菜单中选择“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属性可能小于栅格的列数。
数据源
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。在处理这个事件的句柄中,可以对数据进行校验。