TClientDataSet[3]: 手动建立数据集

//放置控件: ClientDataSet1、DataSource1、DBGrid1、Button1, 然后

procedure TForm1.Button1Click(Sender: TObject);
begin
{ 添加字段 }
with ClientDataSet1.FieldDefs.AddFieldDef do
begin
Name := ‘ID’;
DataType := ftInteger;
end;

with ClientDataSet1.FieldDefs.AddFieldDef do
begin
Name := ‘Name’;
DataType := ftString;
Size := 12; { ftString 类型的 Size 默认 20 }
end;

with ClientDataSet1.FieldDefs.AddFieldDef do
begin
Name := ‘Age’;
DataType := ftWord;
end;

with ClientDataSet1.FieldDefs.AddFieldDef do
begin
Name := ‘Sex’;
DataType := ftBoolean;
end;

{ 构建数据集, 不可缺少的一步 }
ClientDataSet1.CreateDataSet;

{ 显示; 如果在设计时已挂接或不需要显示, 可省略下两行 }
DataSource1.DataSet := ClientDataSet1;
DBGrid1.DataSource := DataSource1;

{ 添加数据 }
ClientDataSet1.AppendRecord([1, ‘张三’, 33, True]);
ClientDataSet1.AppendRecord([2, ‘李四’, 44, False]);
ClientDataSet1.AppendRecord([3, ‘王五’, 55, True]);

{ 保存为 cds 或 XML }
ClientDataSet1.SaveToFile(‘C:\Temp\TestBinary.cds’);
ClientDataSet1.SaveToFile(‘C:\Temp\TestXMLUTF8.xml’, dfXMLUTF8);
end;

这个表的设计也可以在设计时完成:

代码可另写为(下面这种方法简单, 但上一种方法可设置更多选项):
procedure TForm1.Button1Click(Sender: TObject);
begin
{ 添加字段 }
with ClientDataSet1.FieldDefs do
begin
Add(‘ID’, ftInteger);
Add(‘Name’, ftString, 12);
Add(‘Age’, ftWord);
Add(‘Sex’, ftBoolean);
end;

{ 构建数据集, 不可缺少的一步 }
ClientDataSet1.CreateDataSet;

{ 显示; 如果在设计时已挂接或不需要显示, 可省略下两行 }
DataSource1.DataSet := ClientDataSet1;
DBGrid1.DataSource := DataSource1;

{ 插入数据 }
ClientDataSet1.InsertRecord([1, ‘张三’, 33, True]);
ClientDataSet1.InsertRecord([2, ‘李四’, 44, False]);
ClientDataSet1.InsertRecord([3, ‘王五’, 55, True]);

{ 保存为 cds 或 XML }
ClientDataSet1.SaveToFile(‘C:\Temp\TestBinary.cds’);
ClientDataSet1.SaveToFile(‘C:\Temp\TestXMLUTF8.xml’, dfXMLUTF8);
end;

习惯了.net的DataTable,便习惯性的认为Delphi中也有类似的东西,结果搞了好久才搞定,看来看去是拿着Delphi实现.net的思想,生搬硬套了,不过倒也解决了一些问题语言间的思想差别还是有的呃。
1数据集的创建CreatDataSet: TDataSet;
目标是创建一个类似于DataTable的对象,我们可以指定列的字段,也可以手动添加行。
在Delphi中是用DB.TDataSet来实现的(相当于DataTable,与.net的DataSet可是两个概念啊)。
在这里要用到DBClient.TClientDataSet,至于两者的关系,自己去查吧。
方法如下:
function TForm3.CreateDataSet: TDataSet;
var
dsTemp:TDataSet;
cdsTemp: TClientDataSet;
begin
//初始化
dsTemp := TDataSet.Create(Application);
try
//字段名设置
with dsTemp.FieldDefs do
begin
Add(‘code’,ftString,8);
Add(‘name’,ftString,20);
Add(‘Number’,ftInteger);
end;
//创建DataSet
cdsTemp := TClientDataSet.Create(Application);
if dsTemp.FieldDefs <> nil then
begin
cdsTemp.FieldDefs.Assign(dsTemp.FieldDefs);
cdsTemp.CreateDataSet;
result := (cdsTemp as TDataSet);
end;
finally
//内存释放
dsTemp.Free;
end;
end;
2 数据集数据的添加AddDataToSet;很简单的 打开数据集-添加行-赋值-提交
function TForm3.AddDataToSet(AdsData: TDataSet): TDataSet;
var
intLoop:Integer;
begin
//打开数据集
AdsData.Open;
with AdsData do
begin
for intLoop := 0 to 10 do
begin
Append;//添加
FieldByName(‘Code’).AsString := ‘Code’ + intToStr(intLoop);
FieldByName(‘Name’).AsString := ‘Name’ + intToStr(intLoop);
FieldByName(‘Code’).AsInteger := intLoop;
post;//提交
end;
end;
end;
3 修改数据集中某个Field的值 ChangeDataSetValue。这个在.net中可以直接改,不过在这里还是有区别的。这里我们把刚才建的数据集中Name Field的值给改掉
示例代码如下:
AdsData.Open; //打开
AdsData.First;
while Not AdsData.Eof do
begin
AdsData.FieldByName(‘Name’).ReadOnly := false; //只读属性修改
AdsData.Edit; //打开编辑
AdsData.FieldByName(‘Name’).AsString := ‘NewName’; //修改
AdsData.Post; //提交
AdsData.Next;
end;

==========================================

1.1Delphi数据库应用程序的层次结构
Delphi数据库应用程序通过数据存取构件对数据库进行访问,通过可视的数据构件(Data Control)将数据呈现给用户,并与用户进行交互。Delphi数据库应用程序的结构如下图:

图 2?1 Delphi数据库应用程序结构图
Delphi访问数据库可以分为三级:
(1)、由ADO(Active Data Object)对象及底层数据库驱动程序来访问数据源。
(2)、再由数据集构件(TADOTable、TADOQuery、TADODataSet)与ADO对象进行通信。
(3)、构件TDataSource作为数据集构件与数据感知构件(TDBEdit、TDBText、TDBCheck、…)之间的桥梁,负责将来自数据集构件的数据传送给数据感知构件。

图 2?2 数据感知组件、DataSource、数据集对象及数据库四者之间关系及属性设置
1.2什么是数据集
1.2.1什么是数据集?
数据集,在Delphi中就是具有TDataSet类型的对象。
数据集是把数据库中的数据映射到内存缓存中的所构成的数据容器。从数据库抽取数据后,DataSet就是数据的存放地,所以有时说DataSet可以看成是一个数据容器,同时它在客户端实现读取、更新数据库等过程中起到了中间部件的作用。如果省略上图中的DataSource组件,就得到下图:

图 2?3 什么是数据集
在Delphi中,应用程序都是通过各类数据集构件(如:TADOTable、TADOQuery、TADODataSet等)来存取数据库中的数据,所以,掌握数据集构件的使用,对开发数据库应用程序至关重要。

1.2.2数据集构件的继承关系
所有数据集构件都是由TDataSet继承而来,但由于TDataSet是一个抽象类,所以不能直接由此创建对象并使用它(如同TStrings类),而必须使用其派生类,如:TADOTable、TADOQuery、TADODataSet和TADOStoredProc 等。这些派生类统称为“数据集构件”,位于ADO 组件面板上。
这些数据集构件都是从一个共同的父类TDataSet继承下来的,其继承关系可以用图3.1来表示。
  
图 2?4 数据集构件的继承关系
正因为TADOTable、TADOQuery、TADODataSet和TADOStoredProc都是从TDataSet继承而来的,因而这四个构件具有许多相同的属性、方法、事件,这些属性、方法、事件我们会在随后的各章节中结合例子逐渐介绍。
在后面各章节中,我们会大量用到TADOTable、TADOQuery、TADODataSet和TADOStoredProc这四类数据集构件。
1.3数据集的记录位置
1.3.1改变记录位置

在第一个例子中我们看到,当单击DBNavigator构件上的“首记录”、“前一条记录”、“后一条记录”、“尾记录”按钮时,DBGrid构件左边有一个三角形标记“?”,该标记用于指示当前记录位置。
我们在存取或删除记录时,都是以一条记录为单位,即:我们只能存取或删除当前那条记录。
当我们打开一张表时,当前记录位置总是在第一条记录上。如果要改变记录位置,可以使用以下几种方法:
(1)、鼠标单击DBGrid构件中的某一行(或用光标键将当前光标移到某一行),则该行记录就成为当前记录。
(2)、DBNavigator构件上的四个按钮。
(3)、使用数据集构件的五个方法:

方 法
说 明
First
将当前记录位置移至首记录
Prior
将当前记录位置移至上一条记录
Next
将当前记录位置移至下一条记录
Last
将当前记录位置移至尾记录
MoveBy
将当前记录位置向前/后移动若干个位置

例 2?1使用上述数据集构件ADOTable的5个方法程序来移动记录。

图 2?5 移动记录指针
4个命令按钮的OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject); //首记录
begin
ADOTable1.First;
end;

procedure TForm1.Button2Click(Sender: TObject); //上一条
begin
ADOTable1.Prior;
end;

procedure TForm1.Button3Click(Sender: TObject); //下一条
begin
ADOTable1.Next;
end;

procedure TForm1.Button4Click(Sender: TObject); //尾记录
begin
ADOTable1.Last;
end;

1.3.2数据集构件的BOF与EOF属性

这两个属性具有逻辑值,即其值为True或False。当出现下列几种情况时,BOF(EOF)属性值变为True:
操  作
结  果
执行First方法
BOF值变为True
执行Prior方法并超出首记录位置时
BOF值变为True
执行Last方法
EOF值变为True
执行Next方法并超出尾记录位置时
EOF值变为True
打开空表时(没有任何记录)
BOF、EOF值均变为True

其余情况下,BOF与EOF属性值总是False。
我们需要遍历表中所有记录时,可以利用这两个属性。
例 2?2统计出Students.mdb数据库的Students表中的姓“廖”的记录数。

图 2?6 统计表中满足条件的记录数
“统计”命令按钮的OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
var s:integer;
begin
s:=0;
while not adotable1.Eof do
begin
if pos(‘廖’,adotable1.FieldByName(‘姓名’).AsString)>0 then
Inc(s);
adotable1.Next;
end;
edit1.Text:=inttostr(s);
end;

另外,数据集构件有一个RecordCount属性,它返回数据集中记录的总数。使用该属性,上述程序也可以改写为:
for i:=1 to adotable1.RecordCount do
begin
……
end;
1.4数据集的字段对象
数据集构件有一个Fields属性,该属性是一个下标从0开始的数组,数组的每个元素代表数据集构件中的各个字段。例如:Fields[0]代表第一个字段、Fields[1] 代表第二个字段、… 。而每个Fields[i]又是一个TField类型的对象(称为字段对象)。熟悉并掌握字段对象的使用,对于熟练使用Delphi开发数据库应用程序具有十分重要的意义。
1.4.1 字段对象(TField)的属性
这是一个非可视的对象,因而并不出现在Delphi的组件面板上。它的许多属性描述了数据集中每一列的数据类型、当前值、编辑格式等。
缺省情况下,每次在数据集构件激活时(即:打开数据集),Delphi自动为数据集中的每个字段分别创建一个TField对象,关闭数据集时,这些字段对象便释放掉,因而称为临时性字段对象。

TField对象的几个常用属性
属 性
说 明
FieldName
字段名
Index
字段在数据集中的序数值
Value
字段值(根据不同的字段类型,字段值的数据类型也不同)
Text
数据感知构件处于编辑状态时所显示的文本(字符串类型)
IsNull
字段值是否为空值

例 2?3列出Students.mdb数据库的Students表中所有的字段。

图 2?7 列出表中字段
这个例子中,由于不需要使用数据感知构件,所以就没有必要使用DataSource构件,只要一个数据集构件ADOTable就行了。
创建应用程序界面之后,添加命令按钮Button1的OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
for i:=0 to adotable1.FieldCount-1 do
ListBox1.Items.Add(adotable1.Fields[i].FieldName);
end;

注意
此处用到了数据集构件的一个属性FieldCount,它表示数据集中所包含的字段数。另外,应注意:字段对象Fields[i]的数组下标是从0开始的!

利用字段对象Fields[i]的Value属性可以获取字段值。如想要取得表Students中第i个字段的值并显示在编辑框Edit1中,可以执行:
Edit1.text:=ADOTable1.Fields[i].Value;

但更好的方法是使用如下的几个属性:TField对象的数据转化属性
属 性
说 明
AsBoolean
将当前字段值转换为布尔类型
AsDateTime
将当前字段值转换为日期类型
AsFloat
将当前字段值转换为浮点类型
AsInteger
将当前字段值转换为整数类型
AsString
将当前字段值转换为字符串类型

这些属性同样表示字段值,且自动会转换成你所需要的数据类型。
所以,上述代码可改为:Edit1.text:=ADOTable1.Fields[1].AsString;

1.4.2 字段对象(TField)的几种表示形式
字段对象表示形式可以有如下几种表示形式:
(1)、ADOTable1.Fields[i]
这里,Fields[i]是数据集构件ADOTable的属性,并且是数组属性,下标从0开始。

(2)、ADOTable1.FieldByName(<字段名>)
这里,FieldByName是数据集构件的一个方法,该方法返回值即为由<字段名>指定的那个字段对象。

(3)、ADOTable1.FindField(<字段名>)
FindField也是一个方法,与FieldByName基本相同,唯一不同之处是,FindField中如果指定的字段不存在,则返回Nil(空指针)。

当知道字段名时,用(2)比较合适;反之当不知道字段名,而只知道字段的顺序号时,则只能使用(1)。再有,当要求列出一张表中的全部字段时,也只能使用(1)的办法,通过一个循环来实现(见上一个例子)。

1.4.3获取字段值的几种方法

通过字段对象获取字段值的几种办法:

(1)、使用<字段对象>.Value或<字段对象>.AsString、<字段对象>.AsInteger、….等
如前面所提到的ADOTable1.Fields[1].AsString
或ADOTable1.FieldByName(‘姓名’).AsString

(2)使用数据集构件的FieldValues属性,该属性也是一个数组属性,下标从0开始。
如:ADOTable1.FieldValues[‘姓名’]
就表示当前记录的姓名字段的字段值。
由于FieldValues是数据集构件的默认属性,所以可省略FieldValues,而直接写成
ADOTable1 [‘姓名’]
这种写法较为简洁,推荐读者使用。

TFields部件对应于数据库表中的实际字段,它既可以在应用程序的运行过程中动态地生成也可以在程序设计阶段用字段编辑器创建。它是不可见的部件,在程序中我们可以通过TField部件来访问数据库记录的各个字段值。

1.4.4 永久字段对象
1、动态字段对象
默认情况下,当把一个数据集构件(如:ADOTable)放到窗体上并且打开它时,Delphi 就会为数据集中的每一个字段自动生成一个动态的字段对象。之所以说它是动态的,一方面是因为它是自动生成的,另一方面是因为它总是反映物理数据集的情况,对于不同类型的字段来说,生成的字段对象的类型也不同。如果数据集的结构或其他信息发生变化,当应用程序重新打开这个数据集时,就会基于最新的结构和信息重建所有的字段对象。
前面所讲到的字段对象的几种表示方法中,都是动态字段对象。动态字段对象的生存期是临时的,当数据集关闭时,这些字段对象也跟着消失。
动态字段对象的不足之处是,要改变字段的显示属性、数据格式,需编写代码。即使你愿意写代码,无论如何也无法改变字段的显示顺序,不能把某些字段暂时隐去,也不能增加新的字段如“计算字段”、“Lookup字段”。而且,也不能改变字段的数据类型。所以,很多情况下,应用程序往往要用永久字段对象来代替动态字段对象。
2、 永久字段对象
用永久字段对象代替动态字段对象的最大好处是,可以在设计期设置它的属性。此外,永久字段对象还具有以下优势:
u 可以选择部分字段;
u 可以增加新的字段,包括“计算字段”和“Lookup字段”;
u 可以改变原有字段的数据类型。

3、 怎样创建永久字段对象
要创建永久字段对象,就要用到字段编辑器。创建永久字段对象的一般步骤是:
双击窗体中的数据集构件ADOTable,就会打开字段编辑器,这时,字段编辑器窗口中是空的,也就是说我们还没有创建任何永久性的字段对象。

图 2?8 字段编辑器窗口
再在字段编辑器窗口中单击右键,弹出快捷菜单,选择其中的

图 2?9 添加字段快捷菜单
“Add Fields…”:选择这个命令会出现“Add Fields”窗口,窗口中显示的是当前数据集构件所连接的数据库表中的所有字段,我们可以选取需要的字段,将它们加入到字段编辑器窗口中。

图 2?10 向字段编辑器窗口添加字段
“New Fields…”:选择这个命令,将会出现“New Field”对话框,在对话框中可以新增“计算字段”和“Lookup字段”(后面章节将作介绍)。

图 2?11 新字段对话框
“Add all Fields…”:当前数据集构件所连接的数据库表中的所有字段都加入到字段编辑器窗口中。
已经添加到字段编辑器窗口中永久字段对象,如果觉得不需要,可以删除,方法是:重新打开字段编辑器窗口,选中所要删除的字段对象,按 键即可。
4、 使用永久字段对象自动在窗体上创建数据感知构件
双击数据集构件ADOTable,打开字段编辑器窗口,选中其中的永久性字段对象,将其拖放到窗体上,Delphi会首先自动创建一个DataSource构件,然后自动给每个字段创建一个合适的数据感知构件,并自动设置每个数据感知构件的DataSource属性与。

图 2?12 将字段编辑器中的永久性字段拖放到窗口上

图 2?13 自动创建相应的数据感知构件
这样,对于设计一些数据录入窗体,可以大大减少程序设计者的工作量。

5、 永久字段对象所属的数据类型
我们知道,Delphi中,所有变量都具有某种类型(Integer、String、Boolean等);同样,所有对象也都具有各自的类型(对象的类型有个特别的名称,称为“类”-Class)。
动态字段对象都只有一个笼统的类型:TField,没有具体的类型。而永久性字段对象则具有具体的数据类型。如:当使用字段编辑器创建如图 2?14所示的永久性字段对象后,选择该字段对象,就会在Object Inspector窗口中看到该字段对象的名称及所属的数据类型。

图 2?14 永久性字段对象的数据类型

从图 2?14可以看到jbgz字段所对应的字段对象名称为:ADOTable1jbgz,该名称是Delphi自动给出的,而这个字段对象的数据类型为:TIntegerField,这个类型其实是从TField类型继承下来的(不是直接继承)。见图 2?15所示。

图 2?15 字段对象的继承关系
前面讲到,要引用字段对象,可以使用ADOTable1.Fields[i]或ADOTable1.FieldByName( ),现在,当我们创建了永久性字段对象后,还可以直接使用永久字段对象名来引用该字段对象。如:要取得图 2?15中jbgz字段的值,除了可以使用
ADOTable1.Fields[5].AsString 或
ADOTable1.ByName(‘jbgz’).AsString
还可以直接使用ADOTable1jbgz.AsString 。

另外,搞清楚上述概念后,在代码编辑窗口书写程序,当输入:
ADOTable1.FieldByName(‘jbgz’).
之后,Delphi自动弹出的属性、事件、方法列表与输入:
ADOTable1jbgz.
之后弹出的属性、事件、方法列表可能不完全相同,这是因为ADOTable1jbgz对象是从TField继承下来的,比TField类型的对象具有更多的属性、事件、方法可供使用。

注意
已经使用字段编辑器创建了永久性字段对象后,如果再去更改表结构,将会触发异常。必须先删除永久性字段对象,才能更改表结构。

1.5数据集中记录的增加、删除、编辑
1.5.1添加记录
步骤:
(1)、调用数据集构件的Append方法或Insert方法,添加一条空白记录,然后用手工方式或通过执行如下代码来填入内容:
ADOTable1[‘字段名’]:=<表达式>
(2)、调用数据集构件的Post方法,将缓冲区中的数据真正写入表中:
ADOTable1.Post
另外,通过移动记录位置也可以将缓冲区中的数据写入表中。例如:在DBGrid构件中直接用手工方式输入记录时,每输完一条记录后,直接将光标移到下一行,则上一行记录便自动保存,而无需执行Post方法。

注:在执行Post方法之前,如果想撤消所填入的内容,则可执行Cancel 方法来达此目的:
ADOTable1.Cancel

1.5.2 编辑记录
对于少量一更改,可以在DBGrid中通过手工方式来逐条更改记录,但如果是批量更改,则需要用程序来实现,而手工方式的效率太低了。
通过程序实现记录更改,其步骤为:
(1)、调用数据集构件的First、Prior、Next、Last方法,将记录指针移到所要更改的那条记录上。
(2)、调用Edit方法,使数据集构件处于编辑状态。
(3)、通过如下赋值语句:
ADOTable1[‘字段名’]:=<表达式>
给指定的字段赋值。
(4)、执行Post方法,将缓冲区中的数据真正写入表中。
例2?4将Employee.mdb数据库的Employee表中凡所属县市为“台北市”的职工“目前月薪资”增加100元。

图 2?16 批量更新记录
命令按钮Button1的OnClick的事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
while not adotable1.Eof do
begin
if adotable1[‘县市’]=’台北市’ then
begin
adotable1.Edit;
adotable1.FieldByName(
‘目前月薪资’).asinteger:=adotable1.FieldByName(‘目前月薪资’).asinteger+100;
adotable1.Post;
end;
adotable1.Next;
end;
showmessage(‘数据处理完毕!’);
end;
在后面学了SQL-UPDATE命令后,上述程序就可以用一条命令来代替。

1.5.3 删除记录

要删除一条记录,只要执行数据集构件的Delete方法。该方法可以删除当前记录指针所指的那条记录。
当然,在删除记录之前,最好先提示用户:是否真的要删除该条记录?
如:
if application.MessageBox(‘是否真的要删除当前记录?’,
‘警告’,MB_OKCANCEL+MB_ICONQUESTION)=IDOK then
begin
ADOTable1.delete;
ShowMessage(‘记录已删除!’);
end;

注意
当不需要数据感知组件来显示表中记录时,就可以不用DataSource 组件。

1.6 查找数据
1.6.1 Locate方法
数据集构件有一个用于按条件快速定位记录位置的方法:Locate。该方法声明如下:

function Locate(const KeyFields: String; const KeyValues: Variant; Options: TLocateOptions): Boolean;

该方法是一个函数,具有返回值:当查找到满足条件的记录时,返回True;否则返回False。
函数的各个参数说明如下:
KeyFields:所要查找的字段名
KeyValues:所要查找的字段值
Options:这是一个数据类型为TLocateOptions的参数

TlocateOptions的声明如下:
TLocateOptions= set of (loCaseInsensitive, loPartialKey)

从该声明可以看出,TlocateOptions是一个集合类型,该集合的基类型为枚举类型。所以,TlocateOptions类型的变量可以取的值为:[ ]、[loCaseInsensitive]、[loPartialKey]、[loCaseInsensitive, loPartialKey] ,这四取值分别表示:

u [ ]:查找时,不作任何限制
u [loCaseInsensitive]:查找时,不区分大小写
u [loPartialKey]:查找时,只要部分匹配就算是查找成功
u [loCaseInsensitive, loPartialKey]:查找时,不区分大小写,并且只要部分匹配就算是查找成功。

例2?5在Students.mdb数据库的Students表中根据学生姓名查找记录。

图 2?17 使用数据集构件的Locate方法查找记录
注意:本例无需使用数据感知构件,查找结果只需用Label构件显示即可。

//“查找”命令按钮的OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
if adotable1.Locate(‘姓名’,trim(edit1.Text),[]) then
begin
LblBJZH.Caption:=adotable1[‘班级座号’];
LblXM.Caption:=adotable1[‘姓名’];
LblCSNY.Caption:=adotable1[‘出生年月日’];
LblSFZ.Caption:=adotable1[‘身份证号码’];
LblZZ.Caption:=adotable1[‘住址’];
LblJZ.Caption:=adotable1[‘家长’];
LblDH.Caption:=adotable1[‘电话’];
LblKB.Caption:=adotable1[‘科别’];
end
else
showmessage(‘未找到!’);
end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then Button1Click(nil);
end;

1.6.2记录过滤
使用Locate方法,只能按照是否与某个字段值相匹配的方式来查找记录,如果遇到要查找“语文成绩>60分”这样的情形时,如何实现呢?答案是:使用记录过滤。
数据集构件有一个Filter属性,该属性为字符串类型,只要将查找条件(逻辑表达式)以字符串的形式赋值给该属性,同时再将另一个属性Filtered设置为True就可以了。
如:对于上述查找“语文成绩>60分”的记录,只要执行如下语句:
ADOTable1.Filter:=‘语文>60’;
ADOTable1.Filtered:=True;
这里,因为“语文”是数值类型字段,所以过滤条件就是:‘语文>60’。然而如果是文本类型的字段呢?情况稍微有些复杂。看下面一个例子:

例2?6在Employee.mdb数据库的Employee表中根据县市查找记录。

图 2?18 记录过滤

“过滤”命令按钮的OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
var XianShi:string;
begin
XianShi:= edit1.Text;
adotable1.Filtered:=false;
adotable1.Filter:=’县市=’+””+ XianShi +””;
adotable1.Filtered:=true;
end;

本例中,最难理解的一条语句是:
adotable1.Filter:=’县市=’+””+ XianShi +””

为什么不能写成adotable1.Filter:=’县市= XianShi’ 呢? 因为Filter属性要求过滤条件必需是形如:
<字段名> <关系运算符> <常量>

的一个字符串,如:‘语文>60’,‘数学=80’ 等。但如果要求过滤条件是:
姓名=‘张三’
那么,能不能写成:
‘姓名=‘张三’’

呢?
答案是:不能,这样写会出现语法错误!因为Delphi规定:如果单引号出现在字符串中,则必需要使用连续的两个单引号代替一个单引号。所以,必需写成:

‘姓名=‘‘张三’’’

或者也可以写成:‘姓名=’+‘‘’’+‘张三’+‘‘’’

注意
字符串””+ XianShi +””可以改成QuotedStr(XianShi)。函数QuotedStr能够在字符串的头尾加上一个西文的单引号。

1.6.3 OnFilterRecord事件
将Filtered属性值设为True时,同时将会触发 OnFilterRecord事件,我们可以利用OnFilterRecord事件来完成记录筛选工作。其事件处理程序框架如下:

procedure TForm1.ADOTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin

end;

在OnFilterRecord事件中有一个布尔值的变量Accept,只要将过滤条件赋值给该变量,当OnFilterRecord事件被触发时,就会进行记录筛选,将满足条件的记录显示出来。

例如,可以将例2?6改为:
procedure TForm1.ADOTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
var XianShi:string;
begin
Accept:= DataSet.FieldByName(‘县市’).AsString= edit1.Text;
end;

而在“过滤”命令按钮的OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
adotable1.Filtered:=false;
adotable1.Filtered:=true;
end;
最后再看一个例子:
例2?7设计一个可按各个字段、各个筛选条件进行记录过滤的程序,见图 2?19所示。

图 2?19按各字段、条件进行记录过滤

本程序使用了两个ComboBox组件来让用户选择字段名称与条件符号,还有一个输入条件值的Edit组件,这三者构成了筛选记录的条件式,用户只要单击“筛选”按钮,即可筛选出表内符合条件的记录。
窗体上“字段名称”标签后的ComboBox组件是用来选取表的字段,在程序开始时必须将表中的字段名加入到这个ComboBox组件中,所以在窗体的OnActive事件中编写了如下语句:
procedure TForm1.FormActivate(Sender: TObject);
Var
I:Integer;
begin
for I:=0 to ADOTable1.Fields.Count-1 do
begin
ComboBox1.Items.Add(ADOTable1.Fields[I].FieldName);
end;
end;

另外,直接利用For循环将字段名逐一加到ComboBox中,其中ADOTable1.Fields.Count值表示表中字段的个数,因为它的计数是从1开始,但是我们读取字段名称的数组却是从0开始的。因此需要减1。
至于“条件符号”后的那个ComboBox组件,它的项目内容直接由Items属性设置就可以了,共有:=、>、>=、<、<=、<> 6项。
选择好字段名称、条件符号并在条件值中输入筛选的字段数据值后,当单击“筛选”按钮时,并不是进行筛选操作,而是进行筛选条件的变量指定,为了让我们指定的各总分筛选条件值能顺利地传递给OnFilterRecord事件,应先声明两个全局变量来记录字段名称与条件值3个字段的内容,如图?所示。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值