第十四章 简单数据库应用的创建及MASTAPP介绍(二)
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的类型也是字符串型的, 因而它们是匹配的。如果类型不匹配,则要经过一定的转换才能够相互赋值。如:
Edit1.Text:=Table1CustNo.Value
这条代码在运行过程中将会出错,因为TablelcustNo是TFloatField 类型即是数值型数据,要在编辑框Edit1中显示数值型数据要经过下列转换:
Edit1.text:=Table1CustNo.AsString;
AsString是字段对象的属性,通过字段对象的AsString属性可以读取字段值并且将它转换成字符串类型。字段对象的字段值可以转换成以下几种类型的数据:
AsString: 将字段值转换成字符串数据
AsBoolean: 将字段值转换成布尔型数据
AsDateTime: 将字段值转换成日期时间数据
AsFloat: 将字段值转换成数值型数据
AsInteger: 将字段值转换成整数型数据
下面的程序代码是从字段对象中读取字段值并将它显示在编辑框Edit1中, 或者将字段值赋给相匹配的变量。
CustNoDouble: Double;
CustNoInt: Integer;
CustNoString: String;
{在Edit1中显示字段值}
Edit1.Text:=Table1Company;{类型相匹配,不需要转换}
Edit1.Text:=Table1CustNo.AsString;{类型不匹配,需要转换}
{将字段值赋给变量}
CustNoDouble:=Table1CustNo.Value;{类型相匹配,不需要转换}
CustNoInt:=Table1CustNo.AsInteger;{类型不匹配,需要转换}
CustNoString:=Table1CustNo.AsString;{类型不匹配,需要转换}
14.4.5 设定字段对象的显示格式
我们即可以在设计阶段设定字段对象的显示格式,也可以在运行过程中通过程序代码来设定字段对象的显示格式。
例14.2 在如图14.10所示的窗体中,再增加一个TaxRate字段, 并在程序设计过程中设定它的显示格式为0.00%,即设置TaxRate字段对象的DisplayFormat属性为0.00% , 若TaxRate的值为0.085那么在网格部件中其显示的格式为8.50%。
在运行过程中我们通过程序代码来设定字段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是如何工作的。