可能你不知道的TClientDataset功能(转)
TClientDataSet用法与简介
TClientDataSet用法与简介与TTable、TQuery一样,TClientDataSet也是从TDataSet继承下来的,它通常用于多层体系结构的客户端。
TClientDataSet最大的特点是它不依赖于BDE(Borland Database Engine),但它需要一个动态链接库的支持,这个动态链接库叫DBCLIENT.DLL。
在客户端,也不需要用TDatabase构件,因为客户端并不直接连接数据库。
由于TClientDataSet是从TDataSet继承下来的,所以,它支持诸如编辑、搜索、浏览、纠错、过滤等功能。
由于TClientDataSet在内存中建立了数据的本地副本,上述操作的执行速度很快。
也正是由于TClientDataSet并不直接连接数据库,因此,客户程序必须提供获取数据的机制。
在Delphi 4中,TClientDataSet有三种途径获取数据:.从文件中存取数据。
.从本地的另一个数据集中获取数据。
.通过IProvider接口从远程数据库服务器获取数据。
在一个客户程序中,可以同时运用上述三种机制获取数据。
11.1 浏览和编辑数据和其他数据集构件一样,可以用标准的数据控件显示由TClientDataSet引入的数据集,当然,这需要借助于TDataSource构件。
由于TClientDataSet是从TDataSet继承下来的,所以,凡是其他数据集构件支持的功能,TClientDataSet构件也大致具备。
不同的是,TClientDataSet能够在内存中建立数据的副本,因此,TClientDataSet比其他数据集构件增加了一些特殊的功能。
11.1.1 浏览数据可以用标准的数据控件显示由TClientDataSet引入的数据集。
在运行期,可以调用诸如First、GotoKey、Last、Next和Prior等函数来浏览数据。
TClientDataSet也支持书签功能,可以用书签来标记某条记录,以后就可以方便地找到这条记录。
cclientdc用法
cclientdc用法CClientDC是MFC编程中很常用的一个类,用于获取设备上下文(DC),并在此基础上进行绘图操作。
本文将分步骤阐述CClientDC的用法,并介绍一些注意事项,以帮助读者更好地理解和使用这个类。
1. 获取设备上下文CClientDC的主要作用是获取设备上下文,可通过以下语句实现:```CClientDC dc(this);```其中,this代表当前的窗口句柄。
通过这句话,就可以获取到表示窗口客户区的设备上下文,从而可以在此基础上进行绘图操作。
2. 绘制图形CClientDC提供了许多绘图函数,例如LineTo、Rectangle、Ellipse等等。
这些函数的用法和常规的GDI函数相似,只需要在设备上下文上调用相应函数即可。
例如,绘制一条连接屏幕左上角和右下角的直线,可以使用以下语句:```dc.LineTo(GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_C YSCREEN));```其中,GetSystemMetrics函数可以获取到当前屏幕的宽度(SM_CXSCREEN)和高度(SM_CYSCREEN)。
3. 注意事项在使用CClientDC进行绘图时,需要注意以下几点:(1)CClientDC必须在WM_PAINT消息中使用。
也就是说,只有在窗口需要重绘时,才能使用CClientDC。
否则,可能会引起屏幕闪烁等问题。
因此,在调用CClientDC之前,应该先判断是否需要进行绘图操作。
(2)当窗口的大小发生改变时,设备上下文也需要重新获取。
因此,应该在WM_SIZE消息中重新获取CClientDC。
(3)设备上下文是一种系统资源,使用完毕需要及时释放。
CClientDC获取的设备上下文会在离开作用域时自动释放,但是如果在作用域内手动释放了设备上下文,则可能会引起内存泄漏等问题。
(4)在使用CClientDC进行绘图时,应该尽量减少GDI操作的次数,以提高性能。
TClientDataSet的使用技巧
(出处:)
TClientDataSet的使用技巧
在三层结构中,TClientDataSet的地位是不可估量的,她的使用正确与否,是十分关键的,
本文从以下几个方面阐述她的使用,希望对你有所帮助.
1.动态索引
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
if (not column.Field is Tblobfield) then//Tblobfield不能索引,二进制
ClientDataSet1.IndexFieldNames:=column.Field.FieldName;
end;
2.多层结构中主从表的实现
设主表ClientDataSet1.packetrecord为-1,所有记录
(2)使用Aggergates属性add设计表达试
调用
showmessage(floattostr(ClientDataSet1.Aggregates.Count));
showmessage(ClientDataSet1.Aggregates.Items[0].Value);
6.可以对data赋值(从另一个数据集取值)
ClientDataSet2.Data:=ClientDataSet1.Data;
ClientDataSet2.Open;
或者
ClientDataSet2.CloneCursor(ClientDataSet1,true);
ClientDataSet2.Open;
则:客户端ClientDataSet
custom indicator指标
custom indicator指标摘要:一、前言二、自定义指标的定义和作用三、自定义指标的优势四、自定义指标的应用领域五、自定义指标的创建方法六、自定义指标的注意事项七、总结正文:一、前言随着科技的飞速发展,数据在各个领域中扮演着越来越重要的角色。
为了更好地分析这些数据,人们研究出了各种指标。
其中,自定义指标(custom indicator)作为一种灵活且具有针对性的分析工具,越来越受到人们的关注。
本文将对自定义指标进行详细介绍。
二、自定义指标的定义和作用自定义指标,是指根据特定需求和目的,对原始数据进行处理、计算和建模,从而得到的一种衡量标准。
它可以反映数据的某些特征,帮助人们更好地理解和分析数据。
自定义指标广泛应用于金融、医疗、教育、科研等多个领域。
三、自定义指标的优势自定义指标具有以下优势:1.针对性强:根据实际需求和目的制定,更具针对性。
2.灵活性高:可以灵活调整计算方法和参数,适应不同场景。
3.可比性好:可以与其他指标进行对比,便于分析和评价。
4.易于理解:通常具有直观的物理意义或实际背景。
四、自定义指标的应用领域自定义指标在各个领域都有广泛应用,例如:1.金融领域:用于衡量股票、债券等金融产品的风险和收益。
2.医疗领域:用于评估患者的健康状况、疗效和预后。
3.教育领域:用于评价学生的学术表现、教师的教学质量等。
4.科研领域:用于衡量研究成果的创新性、实用性等。
五、自定义指标的创建方法创建自定义指标通常包括以下步骤:1.确定需求和目的:明确需要解决的问题和分析目标。
2.选择合适的计算方法:根据需求和目的,选择合适的计算方法,如平均值、标准差、相关系数等。
3.选取合适的参数:根据计算方法,选取合适的参数,如时间范围、样本数量等。
4.实际应用和调整:将自定义指标应用于实际场景,根据反馈结果进行调整和优化。
六、自定义指标的注意事项在创建和使用自定义指标时,需要注意以下几点:1.确保指标的科学性和合理性:自定义指标应符合相关领域的基本原理和规律。
ClientDataSet的使用
ClientDataSet的使用分享人:树军日期:2011/11/17问题描述:测试上阶联动,下阶联动,没有任何变化(B31-111020005)问题原因:排查问题后发现问题出现在数据集qryMPSTB过滤之后,使用next时,数据集并没有滚动到下一条,出问题的代码是:数据集在过滤之后,可以得到两条记录,但是过滤之后使用next时,并没有定位到下一条记录,最后查的原因是因为过滤的时候数据集的IndexFieldNames 是空值导致的,于是加上索引字段:基于以上问题,总结了下ClientDataSet的用法:1.利用Locate进行定位记录function Locate(const KeyFields: string; const KeyValues: Variant;Options: TLocateOptions): Boolean;其中Options参数可以是loCaseInsensitive和loPartialKeyloCaseInsensitive:不区分大小写loPartialKey:部分字符匹配用法例子:CdsBody1.Locate('LC002',mAccoutID,[loCaseInsensitive]) ;CdsBody1.Locate('Name',’李’,[ loPartialKey]) ;2.利用Filter进行过滤记录利用Filter可以在客户端进行过滤筛选记录,避免重新组SQL查询某一条件的记录用法例子:在使用Filter进行过滤记录时,确保clientdataset的IndexFieldNames属性具有值,否则过滤之后,使用first,next等浏览数据时将失效(B31-111020005)3.利用Delta获取数据集发生变化的记录数据集修改,新增,删除的记录都会记录在属性Delta中,可以利用此属性获取。
用法例子;同时可以利用ClientDataset的UpdateStatus方法获取本次数据集更新的种类,是新增的还是修改的,还是删除的usInserted:新增的记录usModified:修改的记录usDeleted:删除的记录4.利用CloneCursor复制数据集的数据和设置procedure CloneCursor(Source: TClientDataSet; Reset: Boolean;KeepSettings: Boolean = False); 利用CloneCursor可以复制另一个数据集的数据,还可以复制另一个数据集的设置,复制的设置有Filter,Filtered,IndexName,ReadOnly ,RemoteServer,ProviderName 等Reset 和KeepSettings 都是False ,则上面的属性都要设置成与源数据集相同Reset为True ,则上面的属性清空Reset为False 且KeepSettings 为True,上面的属性不变,数据操作对于两个数据集的作用相同用法例子:5.利用DATA属性仅复制数据集的数据这种用法常见于凭证中用法例子:6.利用DisableControls和EnableControls屏蔽刷新和进行优化用法例子:7.利用BookMark标记记录用法例子:8.利用FindField判断某个字段是否存在用法例子:。
Delphi三层开发小技巧TClientDataSet的Delta妙用
Delphi三层开发小技巧TClientDataSet的Delta妙用Delphi三层开发小技巧:TClientDataSet的Delta妙用Delphi做三层开发时,很多人都会在客户端放一个TClientDataSet,中间层远程数据模块就对应放一个TDataSetProvider,然后再连起来.其实这种方法很烦琐,而且程序痈肿不甘,不好维护.我们都知道TClientDataSet的Delta属性记录了数据的所有修改,应用它我们就可以方便的实现一个单表更新的通用方法.首先,在中间层添加一个方法,就叫ApplyUpdates吧.方法定义如下:function ApplyUpdates(constUpdateTable:String;Delta:Variant;out err:String):Boolean;参数UpdateTable是指要更新的表名,Delta是指传过来的TClientDataSet的Delta属性,如果更新错误err返回错误的内容.下面实现这个方法,首先在DataModule上放一个Query,Query连上Connection,然后再放一个TDataSetProvider 连Query.代码如下:function TRoDm.ApplyUpdates(constUpdateTable:String;Delta:Variant;out err:String):Boolean; const sql='select * from %s where 1<>1';var sqlstr:string;ErrCount:Integer;beginResult:=False;sqlstr:=Format(sql,[UpdateTable]);tryConn.BeginTrans;Query.Close;Query.sql.text:=sqlstr;Query.open;Provider.ApplyUpdates(Delta,-1,ErrCount);Result:=ErrCount=0;if Result thenmitTranselse Conn.RollbackTrans;excepton E:Exception dobeginConn.RollbackTrans;err:=E.Message;end;end;end;到此,通用的更新方法已经完成了.不过客户端的ClientDataSet还不能查询显示数据,因此,还要写一个查询方法:function QuerySQL(const sqlstr:string;out Data:Variant;out err:String):Boolean;参数sqlstr就是要持行的查询语句,Data返回查询结果,错误时err返回错误消息QuerySQL实现代码如下:function TRoDm.QuerySQL(const sqlstr:string;outData:Variant;out err:String):Boolean;beginResult:=False;tryQuery.close;Query.sql.text:=sqlstr;Query.sql.Open;Data:=Provider.Data;Result:=True;Excepton E:Exception doerr:=E.Message;end;end;到这里,中间层的代码已经完了,客户端的调用就简单了.比如客户端有个数据模块DM,上面放一个DcomConnection 或者SocketConnection,名叫Conn.例如,我们现在要做一个商品管理的功能,在窗体上放一个TClientDataSet叫Cds,放DataSource,DBGrid等,设置好相应的属性.然后在窗体创建(Create事件)时查询回所有数据,代码如下:const sql='select * from xxxx';var Data:Variant;err:String;beginif Dm.Conn.AppServer.QuerySQL(sql,Data,err) then Cds.Data:=Dataelse MessageBox(self.handle,pchar('查询数据出错:'+err),'错误',MB_OK+MB_ICONERROR);end;然后还有"添加","修改","删除"按扭,代码都和我们平时操作一样,比如"添加"按扭的代码:cds.append;cds.fieldbyname('xxx').asinteger:=xxx;//....cds.post;修改,删除也这样写.不过现在还有个小问题是,这个表的主键的生成问题,这里我们不能用自增主键,要自己自己生成主键,这样你还得在中间层写一个中间层生成主键的方法,在"增加"按扭时生调用生成主键,然后再上面的操作.这里不再多说.增删改完后,这时的数据还在客户端的内存里,想保存到远程的中间层服务器就要用到我们刚才的方法了,下面就是"保存"按扭下的代码:var err:string;beginif cds.ChangeCount=0 then exit;//数据没改变就不用提交了if Dm.Conn.AppServer.ApplyUpdates('xxx',cds.Delta,err) then//xxx就是表名了beginMessageBox(self.handle,'保存成功!','提示',MB_OK+MB_ICONINFORMATION);cds.MergeChangeLog;//合并所有改变的数据end else MessageBox(self.handle,pchar('保存出错:'+err),'错误',MB_OK+MB_ICONERROR);end;到此,这篇文章也讲完了.用这个方法,那些单表的基础数据更新还可以写成一个祖先类,只要加一个取得更新表名的虚方法,比如:function TableName:string;virtual;然后其后代只要override这个方法,返回各自的表名,其他的一句代码都不用写.分类: 三层。
setitemdata用法
setitemdata用法setitemdata是一种在编程中常用的函数或方法,用于设置数据项的值。
它通常用于与列表、数组或字典等数据结构相关的操作中。
在本文中,我们将探讨setitemdata的用法以及它在不同编程语言中的应用。
在许多编程语言中,setitemdata是一种用于设置数据项的函数或方法。
它通常接受三个参数:数据结构、索引或键以及要设置的值。
例如,在Python中,我们可以使用setitemdata来设置列表或字典中的特定项的值。
以下是一个示例:```pythonmy_list = [1, 2, 3, 4]my_list.__setitem__(2, 5)print(my_list)```在这个例子中,我们使用setitemdata来设置my_list列表中索引为2的项的值为5。
运行上述代码,将输出结果为[1, 2, 5, 4],表明成功将索引为2的项的值设置为5。
在其他编程语言中,如C++或Java,setitemdata的用法也类似。
它们通常提供了类似的语法和功能,用于设置数组或字典中的特定项的值。
例如,在C++中,我们可以使用setitemdata来设置数组中特定索引的项的值。
以下是一个示例:```cppint my_array[] = {1, 2, 3, 4};my_array[2] = 5;```在这个例子中,我们使用setitemdata来设置my_array数组中索引为2的项的值为5。
这将更新数组的第三个元素,使其值为5。
除了常规的列表或数组,setitemdata还可以用于字典或关联数组。
在这种情况下,我们可以使用键来设置特定项的值。
例如,在Python中,我们可以使用setitemdata来设置字典中特定键的值。
以下是一个示例:```pythonmy_dict = {"name": "John", "age": 25, "city": "New York"}my_dict.__setitem__("age", 30)print(my_dict)```在这个例子中,我们使用setitemdata来设置my_dict字典中键为"age"的项的值为30。
setitemdata用法
setitemdata用法SetItemData是在MFC中常用的一个函数,可以用来在CListCtrl中储存额外的数据信息。
在开发中,我们常常需要在列表控件中存储一些自定义数据,比如说一个序号、一个字符串、一个颜色等等,并在之后需要使用这些数据。
在这种情况下,我们可以使用SetItemData函数来实现。
下面就让我们来详细的了解一下SetItemData函数的使用方法:一、函数定义BOOL SetItemData(int nItem, DWORD_PTR dwData);该函数的参数含义如下:nItem:CListCtrl控件中的行号,从0开始。
dwData:需要储存的DWORD_PTR类型的数据。
二、功能描述SetItemData函数的作用是为CListCtrl控件中的一行,储存一个DWORD_PTR类型的数据。
这个数据就可以在之后的程序运行中被取出,用于其他用途。
该函数的返回值为TRUE和FALSE,表示是否设置成功。
三、使用方法下面是使用SetItemData函数的具体步骤:1)准备好需要存储的数据,比如说序号、字符串、颜色等等。
2)获取需要存储的项的行号(nItem);3)调用SetItemData函数,将数据存储到该项中。
例如,我们可以在对CListCtrl控件进行初始化的代码中添加如下语句:m_listCtrl.InsertColumn(0, _T("序号"), LVCFMT_LEFT, 50); m_listCtrl.InsertColumn(1, _T("姓名"), LVCFMT_LEFT, 100);m_listCtrl.InsertColumn(2, _T("成绩"), LVCFMT_LEFT, 100);m_listCtrl.InsertItem(0, _T("张三"));m_listCtrl.SetItemData(0, (DWORD_PTR) 1);上面的代码向CListCtrl添加了三个列,并向第一行添加了“张三”这个字符串,同时在该行中存储了一个序号“1”。
clientdataset 用法
clientdataset 用法影响ClientDataSet处理速度的一个因素TClientDataSet是Delphi开发数据库时一个非常好的控件。
有很强大的功能。
我常常用ClientDataSet做MemoryDataSet来使用。
还可以将ClientDataSet的数据保存为XML,这样就可以做简单的本地数据库使用。
还有很多功能就不多说了。
在使用ClientDataSet 的过程中关于怎样提高处理速度这个问题,我就我个人的一点点体会和大家分享一下。
通常情况下我们一般都是用...ClientDataSet-->DataSource-->DBComponent这样的结构,处理数据的时候就直接操作ClientDataSet。
但是大多DBComponet都会立即响应ClientDataSet的变化。
如果你是向ClientDataSet中插入很多数据时候,DBComponent 就要响应几次,而且响应过程根据不同的控件,速度,过程数量都不一样。
这样就影响了程序的执行效率。
所以在对ClientDataSet处理中,我是用ClientDataSet.DisableControls 和ClientDataSet.EnableControls方法:打开和关闭DBComponent与ClientDataSet的数据显示关系。
例如:ClientDataSet..DisableControls;...for I := 0 to 10000 dobeginClientDataSet.Append;...ClientDataSet.Post;end;...ClientDataSet.EnableControls...这样做以后你会发现处理速度比以前没有使用方法的时候有成倍的提高。
ClientDataSet的数据查找。
我所介绍的心得和技巧都是用ClientDataSet来做范例,也可以应用于其他的一些DataSet。
TClientDataSet手动修改Data数据
TClientDataSet手动修改Data数据TClientDataSet 手动修改Data数据使用TClientDataSet控件与DBGrid控件编辑显示数据窗口。
在设计过程中,ClientDataSet与DBGrid放置在两个不同的动方,手工连接。
由于ClientDataSet中的数据,部分在DBGrid中要求不显示。
在新增的行中,隐藏的列是必填字段,不能为空值,如果提交到数据库中,当然要报字段不能为空的错了。
要怎么才能手工加入隐藏的字段数据呢?ClientDataSet 有Data与Delte对象,前者为从数据源中取到内存的数据,后然是内存修改数据,等待更新到物理数据源中的数据。
Delte中的数据可以通过创建一个新的ClientDataSet 对象来得到Data,能知道有哪些数据是等待提交的。
但是新的ClientDataSet中的Data不能提交到前者ClientDataSet的Delte里。
这个方法行不通了。
Delte的只能用来查看数据,不能再修改。
再者,如果是修改的数据,那么有两条,怎么判断修改的数据也是个麻烦的事。
所以,Delte 这里行不通。
ClientDataSet有UpdateStatus方法,用来表述Data数据的Modify情况。
哈~~可往这里发展。
UpdateStatus的属性TUpdateStatus = (usUnmodified, usModified, usInserted, usDeleted);Data中的数据,前面讲了,是从数据库中取到的内存数据,但是问题又来了,新的Insert的数据,这里面没有。
怎么办?使用Post,提交到内存数据里面。
只要没有ApplyUpdates过,UpdateStatus的值都没有重置过。
if ClientDataSet.UpdateStatus = TUpdateStatus (usUnmodified, usModified, usInserted, usDeleted) then 来判断行的Modify状态吧。
delphi clientdataset 复制结构
在Delphi 中,使用ClientDataSet 时,如果你想复制其结构(例如字段名称、类型等),你可以使用Clone 方法。
但是,这个方法只会复制数据集的结构,并不会复制其中的数据。
以下是一个简单的示例,展示如何使用Clone 方法来复制ClientDataSet 的结构:
delphi
procedure TForm1.CopyClientDataSet;
var
NewClientDataSet: TClientDataSet;
begin
// 创建新的ClientDataSet 实例
NewClientDataSet := TClientDataSet.Create(nil);
// 复制旧ClientDataSet 的结构到新的ClientDataSet
NewClientDataSet.Clone := True;
NewClientDataSet.DataSet := YourOldClientDataSet;
// 之后你可以使用NewClientDataSet,它会有与YourOldClientDataSet 相同的结构,但无数据
end;
在上面的代码中,YourOldClientDataSet 是你想要复制的原始ClientDataSet 实例。
通过设置NewClientDataSet.Clone := True,并将NewClientDataSet.DataSet 设置为原始ClientDataSet,新的ClientDataSet 将拥有与原始ClientDataSet 相同的结构。
请注意,这只会复制结构,不会复制数据。
如果你也想复制数据,你需要使用Transfer 方法或手动添加数据行。
Delphi中运行期间在TClientDataSet中实现统计字段和计算字段
Delphi中运⾏期间在TClientDataSet中实现统计字段和计算字段1、统计字段的实现第⼀步⽤如下格式创建TClientDataSetwith ClientDataSet1 doBeginwith FieldDefs.AddFieldDef doBeginDataType=ftInteger;Name='A';End;with FieldDefs.AddFieldDef doBeginDataType=ftInteger;Name='B';End;with FieldDefs.AddFieldDef doBeginDataType=ftInteger;Name='C';End;CreateDataSet;Active:=true;End;第⼆步、定义统计字段的计算⽅法Function GetAggVale(CDS:TClientDataSetp;const AggExpression:String;const AggField:String;const AggGroupLevel:Integer=0):Variant;varAddUp:TAggregate;BeginAddup:=TAggregate.Create(CDS.Aggregates,CDS);tryAddup.Expression:=Format(AggExpression,[AggField]);AddUp.GroupingLevel:=AggGroupLevel;Addup.active:=True;Result:=Addup.Value;FinallyAddup.Free;End;End;在ClientDataSet1的AfterPost事件中实现ShowMessage(GetAddValue(ClientDataSet1,'Sum(%s)','A',0);以上是简单说明了⼀下统计字段的简单运⽤,实际上在Delphi中的TClientDataSet还可以实现很多中统计。
ClientDataSet动态创建计算字段Field
ClientDataSet动态创建计算字段FieldClientDataSet 动态创建计算字段 FieldClientDataSet为一个中间件,很好用,但是也有种种问题的出现。
当ClientDataSet是静态创建的,那个,动态创建Field,正常。
varField : TStringField;beginField := TStringField.Create(FClientDataSet);Field.FieldKind := fkCalculated;Field.FieldName := 'State'; := 'State';Field.DataSet := FClientDataSet;end;但是ClientDataSet是动态创建的,那么直接使用上面的代码,将只有这个动态创建的字段,别的字段全部不见了。
怎么办呢?先读取ClientDataSet的提供者所提供的字段,然后再加入之上的代码,那么就可以了,提交数据也正常了。
for i := 0 to FDataSetProvider.DataSet.Fields.Count - 1 dobeginField := TStringField.Create(FClientDataSet);Field.FieldKind := fkData;Field.FieldName:=FDataSetProvider.DataSet.Fields.Fields[i].FieldName;:=FDataSetProvider.DataSet.Fields.Fields[i].Name;Field.DataSet := FClientDataSet;end;网上查了半天都没有找到直接的答案,现在做个笔记吧。
分类: Delphi MIS。
TClientDataSet数据格式化(小计-合计-累计)
TClientDataSet数据格式化(小计-合计-累计)//用于保存表格数据分组统计的规则TGroupT otal=class(TObject)publicItem:Integer; //序号Kind:String; //类型KindT ext:String; //类型名称FidName:String; //统计字段Fids:String; //分组字段GetFid:String; //取值字段FM:String; //公式、格式InitFid:String; //初始值字段KeyValue:String; //用来保存分组字段关键值Value:Double; //用来保存统计结果FidIndex:Integer; //字段下标号end;//规则列表TGroupT otalList=class(TObject)privateFGTList:TObjectList;public//创建类constructor create;//注销类destructor destroy;override;//加入对象procedure AddGTObj(GTObj:TGroupTotal);procedureAdd(aItem:integer;aKind,aKindText,aFidname,aFids,aGetFid,aFM, aInitFid,aKeyValue:String;aValue:Double;aFidIndex:integer);//返回对象function Items(Index:integer):TGroupTotal;//对象数量function Count:integer;//查询是否存在某种类型的统计function KindExists(aKind:String):boolean;end;{ TGroupT otalList }constructor TGroupTotalList.create;begininherited;FGTList:=TObjectList.Create;end;destructor TGroupTotalList.destroy;beginFreeAndNil(FGTList);inherited;end;procedureTGroupT otalList.Add(aItem:integer;aKind,aKindText,aFidname,aFi ds,aGetFid,aFM,aInitFid,aKeyValue:String;aValue:Double;aFidIndex:integer);varGTObj:TGroupTotal;beginGTObj:=TGroupT otal.Create;with GTObj dobeginItem:=aItem;Kind:=aKind;KindT ext:=aKindText;FidName:=aFidName;Fids:=aFids;GetFid:=aGetFid;FM:=aFM;InitFid:=aInitFid;KeyValue:=aKeyValue;Value:=aValue;FidIndex:=aFidIndex;end;FGTList.Add(GTObj);end;procedure TGroupTotalList.AddGTObj(GTObj: TGroupTotal); beginFGTList.Add(GTObj);end;function TGroupT otalList.Count: integer;beginresult:=FGTList.Count;end;function TGroupT otalList.Items(Index: integer): TGroupT otal;beginif FGTList.Count>Index thenresult:=TGroupT otal(FGTList[Index])elseresult:=nil;end;//查询是否存在某种类型的统计function TGroupT otalList.KindExists(aKind: String): boolean;vari:integer;beginresult:=false;for i:=0 to FGTList.Count-1 doif TGroupTotal(FGTList[i]).Kind=aKind thenbeginresult:=true;break;end;end;//=================== 格式化数据=============================function FormatData(aDataSet: TClientDataSet): boolean;varFData,DataSet:TClientDataSet;Fids:TStrings;FidName,KeyValue,aSQL,MsgStr:string;IsAppend,flag:boolean;i,Recs,FidIndex,K,KindFid:integer;tmpData,ErrMsg:OleVariant;GTList:TGroupT otalList;GTObj:TGroupTotal;//处理小计procedure SubT otal(IsEof:boolean=false);varj,l:integer;FGTObj:TGroupTotal;begin//处理小计IsAppend:=false;Flag:=false;for l:=0 to GTList.Count-1 dobeginFGTObj:=GTList.Items(l);if FGTObj.Kind ='1' thenbeginFidName:=trim(FGTObj.FidName);Fids.Text:=trim(FGTObj.Fids);FidIndex:=FGTObj.FidIndex;//分组关键值KeyValue:='';if Flag and (not IsEof) thenDataSet.Next;for j:=0 to Fids.Count-1 doKeyValue:=KeyValue+trim(DataSet.FieldByName(Fids[j]).AsString);if Flag and (not IsEof) thenDataSet.Prior;//小计if IsEof or ((FGTObj.KeyValue<>'')and(FGTObj.KeyValue<>KeyValue)) then beginif IsAppend thenbeginDataSet.Edit;endelsebeginif IsEof thenDataSet.AppendelseDataSet.Insert;IsAppend:=true;Flag:=true;if KindFid<>-1 thenDataSet.Fields[KindFid].AsString:=FGTObj.KindText;end;DataSet.Fields[FidIndex].AsFloat:=FGTObj.Value;DataSet.Post;//小计值清零FGTObj.Value:=0;end;end;if Flag and (not IsEof) thenDataSet.Next;end;beginresult:=false;if aDataSet.IsEmpty thenexit;//定义的规则数据FData:=TClientDataSet.Create(nil);FData.Data:=FSFData.Data;if FData.RecordCount=0 thenbeginFData.Free;exit;end;DataSet:=TClientDataSet.Create(nil);DataSet.Data:=aDataSet.Data;Fids:=TStringList.Create;GTList:=TGroupTotalList.create;NotExec:=true;tryFData.First;while not FData.Eof dobeginifDataSet.FindField(FData.FieldByName('FIDNAME').AsString)<>ni l thenGTList.Add(FData.FieldByName('ITEM').AsInteger,FData.FieldByName('KND').AsString,FData.FieldByName('KNDTEXT').AsString,FData.FieldByName('FIDNAME').AsString,SplitString(FData.FieldByName('FIDS').AsString,',',true),FData.FieldByName('GETFID').AsString,FData.FieldByName('FM').AsString,FData.FieldByName('INITFID').AsString,'',0,DataSet.FindField(FData.FieldByName('FIDNAME').AsString). Index);DataSet.FieldByName(FData.FieldByName('FIDNAME').AsStri ng).ReadOnly:=false;end;FData.Next;end;//类型描述字段,KindFid:查询出第一个字符类型的字段,用于显示小计、合计等字符KindFid:=-1;for k:=0 to DataSet.FieldCount-1 dobeginif (DataSet.Fields[k].DataType in [ftString,ftWideString]) then beginKindFid:=k;if DataSet.Fields[k].Size>=4 thenbreak;end;end;//============== 处理数据 =============DataSet.First;//处理小计和累计if GTList.KindExists('1') or GTList.KindExists('2') or GTList.KindExists('3') or GTList.KindExists('9')thenbeginwhile not DataSet.Eof dobeginIsAppend:=false;for K:=0 to GTList.Count-1 dobeginGTObj:=GTList.Items(K);FidName:=trim(GTObj.FidName);Fids.Text:=Trim(GTObj.Fids);FidIndex:=GTObj.FidIndex;//分组关键值KeyValue:='';for i:=0 to Fids.Count-1 doKeyValue:=KeyValue+trim(DataSet.FieldByName(Fids[i]).AsS tring);//KND: 1.小计 2.合计case StrToIntDef(trim(GTObj.Kind),0) of1,2:begin//小计、合计//清零if(DataSet.RecNo=1)or((Fids.Count>0)and(GTObj.KeyValue<>'')an d(GTObj.KeyValue<>KeyValue)) thenbeginGTObj.Value:=0;if (GTObj.InitFid<>'') then //初始值GTObj.Value:=DataSet.FieldByName(GTObj.InitFid).AsFloat;end;GTObj.Value:=GTObj.Value+DataSet.Fields[FidIndex].AsFloat;GTObj.KeyValue:=KeyValue;end;3:begin // 3.累计//清零if(DataSet.RecNo=1)or((Fids.Count>0)and(GTObj.KeyValue<>'')an d(GTObj.KeyValue<>KeyValue)) thenbeginGTObj.Value:=0;//初始值if (GTObj.InitFid<>'') thenGTObj.Value:=DataSet.FieldByName(GTObj.InitFid).AsFloat;end;if GTObj.GetFid<>'' thenGTObj.Value:=GTObj.Value+DataSet.FieldByName(GTObj.Ge tFid).AsFloatelse if GTObj.FM<>'' thenbeginCData.EmptyDataSet;CData.Append;for i:=0 to CData.FieldCount-1 doCData.Fields[i].Value:=DataSet.Fields[i].Value;CData.Post;GTObj.Value:=GTObj.Value+ExprObj.Execute(GTObj.FM,Datas);end;GTObj.KeyValue:=KeyValue;DataSet.Edit;DataSet.Fields[FidIndex].AsFloat:=GTObj.Value;DataSet.Post;end;9://序号beginDataSet.Edit;DataSet.Fields[FidIndex].AsInteger:=DataSet.RecNo;DataSet.Post;end;end;end;DataSet.Next;//处理小计SubTotal;end;//处理小计SubTotal(true);end;//合计显示IsAppend:=false;for K:=0 to GTList.Count-1 dobeginGTObj:=GTList.Items(K);FidName:=trim(GTObj.FidName);FidIndex:=GTObj.FidIndex;if (GTObj.Kind='2')or(GTObj.Kind='4') thenbeginif IsAppend thenDataSet.EditelsebeginDataSet.Append;IsAppend:=true;if KindFid>=0 thenDataSet.Fields[KindFid].AsString:=GTObj.KindText; end;DataSet.Fields[FidIndex].AsFloat:=GTObj.Value; DataSet.Post;end;end;//记得合并,否则数据赋值回去会把新增的小计排最后面去if DataSet.ChangeCount>0 thenDataSet.MergeChangeLog;aDataSet.Data:=DataSet.Data;result:=true;finallyFData.Free;aDataSet.First;Fids.Free;DataSet.Free;GTList.Free;end;end;。
fdmemtable的emptydataset和close的用法
fdmemtable的emptydataset和close的用法
在Delphi中,TFDMemTable是一个内存数据集,用于存储和处理数据。
它类似于在内存中创建的数据库表,可以进行数据存储、查询和处理。
下面是关于EmptyDataSet和Close方法的详细介绍:
EmptyDataSet方法:
EmptyDataSet方法用于清空TFDMemTable中的数据,使其变为空数据集。
调用这个方法后,数据集中的所有记录都会被删除,但字段结构仍然保留。
示例代码:
FDmemtable1.EmptyDataSet;
Close方法:
Close方法用于关闭TFDMemTable,释放其占用的资源,并清除所有数据。
与EmptyDataSet不同,Close方法会关闭整个数据集,包括字段结构。
示例代码:
FDmemtable1.Close;
使用示例:
加载数据到TFDMemTable
FDQuery1.Open;假设FDQuery1是一个TFDQuery,用于从数据库中获取数据FDmemtable1.Data:=FDQuery1.Data;将查询结果加载到内存数据集
清空数据集
FDmemtable1.EmptyDataSet;
关闭数据集
FDmemtable1.Close;
使用这些方法时要注意,EmptyDataSet只会清空数据,保留字段结构,而Close则会关闭整个数据集,释放所有资源。
根据实际需求选择使用哪个方法。
TCL用法详述
T C L用法祥述一TCL语法1 脚本、命令和单词符号一个TCL脚本可以包含一个或多个命令。
命令之间必须用换行符或分号隔开,下面的两个脚本都是合法的:set a 1set b 2或set a 1;set b 2TCL的每一个命令包含一个或几个单词,第一个单词代表命令名,另外的单词则是这个命令的参数,单词之间必须用空格或TAB键隔开。
TCL解释器对一个命令的求值过程分为两部分:分析和执行。
在分析阶段,TCL 解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,TCL 解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。
2 置换(substitution)注:在下面的所有章节的例子中,'%'为TCL的命令提示符,输入命令回车后,TCL会在接着的一行输出命令执行结果。
'//'后面是我自己加上的说明,不是例子的一部分。
TCL解释器在分析命令时,把所有的命令参数都当作字符串看待,例如:%set x 10 //定义变量x,并把x的值赋为1010%set y x+100 //y的值是x+100,而不是我们期望的110x+100上例的第二个命令中,x被看作字符串x+100的一部分,如果我们想使用x的值'10' ,就必须告诉TCL解释器:我们在这里期望的是变量x的值,而非字符'x'。
怎么告诉TCL解释器呢,这就要用到TCL语言中提供的置换功能。
TCL提供三种形式的置换:变量置换、命令置换和反斜杠置换。
每种置换都会导致一个或多个单词本身被其他的值所代替。
置换可以发生在包括命令名在内的每一个单词中,而且置换可以嵌套。
1) 变量置换(variable subtitution)变量置换由一个$符号标记,变量置换会导致变量的值插入一个单词中。
fdmemtable的emptydataset和close的用法 -回复
fdmemtable的emptydataset和close的用法-回复在Delphi中,FDMemTable是FireDAC库中的一个组件,用于在内存中存储和操作数据。
它类似于数据库表,但实际上是一个轻量级的数据集,可以方便地操作和检索数据。
在使用FDMemTable时,我们经常会用到两个方法:EmptyDataSet和Close。
本文将一步一步解释这两个方法的用法及其作用。
首先,让我们来了解EmptyDataSet方法。
EmptyDataSet方法是FDMemTable类的一个公共方法,用于清空数据集中的所有数据。
当我们从一个数据源加载数据或者使用其他方法填充数据集后,有时需要清空数据集以容纳新的数据。
使用EmptyDataSet方法可以很方便地实现这一功能。
下面是EmptyDataSet方法的用法示例:FDQuery1.CreateDataSet; 创建数据集...在数据集中加载或填充数据...FDQuery1.EmptyDataSet; 清空数据集在上面的示例中,首先我们使用CreateDataSet方法创建了一个FDQuery1的数据集,然后在接下来的代码中加载或填充数据。
最后,我们使用EmptyDataSet方法清空了该数据集,以便容纳新的数据。
使用EmptyDataSet方法时需要注意以下几点:1. EmptyDataSet方法只会清空数据集中的数据,不会影响数据表的结构。
因此,如果需要同时清空数据集中的数据和数据表的结构,可以使用FDQuery1.Close方法关闭数据集,并重新调用CreateDataSet方法创建一个新的数据集。
2. EmptyDataSet方法执行后,数据集中的游标位置将重置为第一条记录之前的位置。
因此,在清空数据集后需要重新定位到适当的位置,以便进行下一步的操作。
接下来,让我们来了解Close方法。
Close方法是FDDataSet类(包括FDQuery、FDTable、FDStoredProc等)的一个公共方法,用于关闭数据集并释放相关资源。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
可能你不知道的TClientDataset功能(转)delphi学习2009-12-15 11:34 阅读69 评论0字号:大中小keyLife富翁笔记作者: shiningplus标题: delphi Midas SQLServer的自增字段的处理关键字: delphi Midas 自增字段分类: 个人专区密级: 公开(评分: , 回复: 0, 阅读: 1830) ??delphi Midas SQLServer的自增字段的处理1.新增时,表中有自增字段,但是不希望用Refresh,直接ApplyUpdates直接看见自增字段的值在DataSetProvider.AfterUpdateRecord写如下代码DataSetProvider.Options.poPropogateChanges:=True;procedure TForm1.DataSetProvider1AfterUpdateRecord(Sender: TObject;SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;UpdateKind: TUpdateKind);begin//DstId TADODataset//FId 为自增字段if UpdateKind=ukInsert thenbeginmandText:='select @@Identity as FId ';DstId.Open;DeltaDS.FieldByName('FId').ReadOnly:=False;DeltaDS.FieldByName('FId').NewValue:=DstId.FieldByName('FId').AsInteger ;DstId.Close;end;end;2.新增时,从表的关联字段与主表的自增字段同步更新procedure TProducts.DataSetProvider1BeforeUpdateRecord(Sender: TObject;SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;UpdateKind: TUpdateKind; var Applied: Boolean);begin//DstProduct为从表的Name//CategoryID是从表的对于主表的字增自段的关联字段// qryIdentity是TADOQuery qryIdentity.SQL:='select @@identity'if (UpdateKind = ukInsert) and(SourceDS = DstProduct) and(DeltaDS.FieldByName('CategoryID').Value = Unassigned) ) thenbeginif DeltaDS.BOF thenbeginqryIdentity.Close;qryIdentity.Open;end;DeltaDS.FieldByName('CategoryID').NewValue := qryIdentity.Fields[0].Value;end;end;Delphi做为一个快速应用开发工具,深受程序员的喜爱。
其强大的组件功能,让程序员能够轻松、高效地完成常见的界面开发、数据库应用等功能。
然而,帮助的相对缺乏,使得许多组件的功能并不为人们正确地使用,究其原因,仍然是认识上的问题。
对于MIDAS开发中的核心部件,TClientDataSet和TDataSetProvider,由于资料的缺乏,人们在网上大多谈论的是李维的书籍内容。
我有幸在BDN上见到了Cary Jensen的ProfessionalDeveloper系列文章,详细阐述了DELPHI的数据库开发技术。
现节选出其中的ClientDataSet部分,与大家共同分享。
ClientDataSet是一个功能强大的类,通过在内存中模拟表格,实现了其它数据集组件所不具备的强大功能。
以往只在Delphi和C++ Builder企业版中才提供这个组件,如今,Borland的全部产品(包括最新的Kylix)都集成了TClientDataSet组件。
TClientDataSet从类的继承关系上来看,是TDataSet这个抽象类的子类,所以我们可以在TDataSet这个抽象层次上对其进行我们熟悉的操作,比如导航、排序、过滤、编辑。
要注意的是,TClientDataSet使用了一种全新的技术,它将所有的数据均放在内存中,所以TClientDataSet是个只存在内存中的“虚拟表”,因此对数据库的操作是非常快的。
在PIII 850,512MB的机器上对十万条记录进行建索引的操作,花费的时间少于半分钟。
与一般的数据集组件不同,TClientDataSet使用的技术比较特别,本着高速度、低存储需求的原则,TClientDataSet的内部使用了两个数据存储源。
第一个是其Data属性,这是当前内存数据的视图,反映了所有的数据改变。
如果用户从数据中删除一条记录,则此记录将从Data中消失,相应地,加入一条新记录后,此记录便存在Data属性中了。
另一个数据源是Delta属性,故名思义,即增量的意思,这个属性反映了对数据的改变。
无论是向Data属性新增还是删除记录,都会在Delta中记录下来,如果是修改了Data中的记录,则会在Delta保存两条相应的记录,一条是原始记录,另一条仅包含修改的字段值。
正因为Delta的存在和TClientDataSet在内存中记录数据的特点,所有的改变都没有立即更新加对应的物理存储中,可以根据这些信息在适当的时候恢复,所以TClientDataSet天生具有缓冲更新功能。
为了使数据更新回数据存储源,我们要调用TClientDataSet中对应的方法。
如果ClientDataSet与DataSetProvider关联,那么仅需调用TClientDataSet的ApplyUpdates方法即可保存数据的更新,但如果TClientDataSet没有对应的TDataSetProvider存在,而是直接同文件关联,那么,这种方式是非常有趣的,我们在BriefCase模型中会再次讲解这个问题。
此时,如果使用TClientDataSet的SaveT oFile和LoadFromFile,都会保留着Delta。
调用MergeChangeLog和ClearChanges后,Delta的内容才会被清空。
只是前者是将Delta的数据同Data结合起来,将改变存储到物理介质上,而ClearChanges则是一股脑儿全部清空,将数据回复到原始状态。
大部分的应用都是将TClientDataSet与TDataSetProvider结合使用的。
两者联合使用的行为反映了Borland的设计宗旨,就是要提供一个面向分布式环境的思路。
我们下面来慢慢解释。
当我们将TClientDataSet对象的Active属性设为True或者调用其Open方法后,ClientDataSet会向DataSetProvider发送一个取数据包请求。
于是DataSetProvider便会打开对应的数据集,将记录指针指向第一条记录,然后从头到尾依次扫描。
对于扫描到的每一条记录,都会将其编码成一个variant数组,我们通常将它称之为数据包。
完成扫描后,DataSetProvider会关闭指向的数据集,并将所有的这些数据包传递给ClientDataSet。
在我提供的演示程序中,你可以清楚地看到这种行为(毕竟眼见为实吗!)。
程序主界面右边的DBGrid连接到一个指向数据库表的数据源,DataSetProvider即指向此表。
当选择了ClientDataSet | Load菜单项时,你可以看到表格的数据被依次扫描,一旦到达最后一条记录,表格便会被关闭,右边的DBGrid被清空,而左边反映ClientDataSet数据的DBGrid便出显示出内存中的数据来。
由于这个过程会在DBGrid上反映出来,所以不到1000条记录的取出时间中,大部分都浪费在屏幕的更新显示上了,你可以选择ClientDataSet | View Table Loading来禁止显示,而达到加速的目的。
在上面的描述中,我们没有提到一个重要的环节,即数据包是如何还原成表格的。
那是因为DataSetProvider会将数据包中的元数据解码出来,根据元数据(我们可以理解为数据表的结构)便可以构造出与物理数据表一模一样的内存虚拟表。
但要注意的是,尽管DataSetProvider指向的数据表可能有多个索引,但这些信息是不会放在数据包中的,换句话说,ClientDataSet当中的数据默认情况下是无索引的。
但因为ClientDataSet具有与TDataSet一致的行为,所以我们可以在此基础上根据需要重建索引。
在ClientDataSet中的数据被修改后,可以提交给物理数据表持久化这此改变。
这个工作便是由DataSetProvider 完成的。
内部工作原理是:DataSetProvider创建一个TSQLResolver的实例,这个实例会生成要在底层数据上执行更改的SQL语句。
详细地说,就是对修改日志中的每一条被删除、插入、更改记录生成对应的SQL语句。
这个语句的生成也可以由用户控制,DataSetProvider的UpdateMode属性和ClientDataSet中的ProviderFlags属性都对SQL语句的生成有影响。
当然,你也可以换一种方式,即采取同单机或C/S结构一样的数据直接操作机制,绕过SQL语句和缓冲更新机制来修改数据库。
只需将ResolveToDataSet属性设为True,那么DataSetProvider在持久化更新时便不会使用TSQLResolve,而是直接修改物理数据源。
即定位到要删除的记录,调用删除语句,定位到修改记录,调用修改语句。
我们可以对演示程序稍加修改,观察此种行为。
请将演示程序中的DataSetProvider的ResolveToDataSet属性由False改为True,运行。
在界面中修改数据并且保存,你将会看到右边的导航按钮会在瞬间变得可用。
更绝妙的是,Borland考虑到了应用的多样性,为我们提供了BeforeUpdateRecord事件,这样,当DataSetProvider对每个修改日志的记录进行操作时,都会触发此事件,我们可以在此事件中加入自己的处理,如“加密操作”、“商业敏感数据处理”等应用,从而极大地方便了程序员,让程序员对于数据具有完全的控制能力。