clientdataset 遍历字段_delphi – 在DBGrid中移动列似乎移动附加的DataSet字段

我上周观察到我没有想到的,下面将会描述.我很好奇为什么会发生这种情况.它是TDataSet类内部的东西,TDBGrid的工件还是其他东西?

打开的ClientDataSet中的字段顺序发生变化.具体来说,我通过使用FieldDefs定义其结构后调用CreateDatatSet在代码中创建了一个ClientDataSet.此ClientDataSet结构中的第一个字段是名为StartOfWeek的Date字段.只有片刻之后,我还写过的代码,其中假设StartOfWeek字段处于零位置,ClientDataSet.Fields [0]失败,因为StartOfWeek字段不再是ClientDataSet中的第一个字段.

经过一番调查,我了解到,ClientDataSet中的每一个字段都可能在给定的时刻出现在创建ClientDataSet时与原始结构不同的位置.我不知道这可能会发生,谷歌搜索也没有提到这个效果.

发生了什么不是魔术这些字段本身并没有改变位置,也没有根据我在代码中所做的任何改变.导致这些字段在ClientDataSet中实际出现更改位置的原因是,用户已经更改了ClientDataSet所附加的DbGrid中的列(当然是通过DataSource组件)的顺序.我在Delphi 7,Delphi 2007和Delphi 2010中复制了这个效果.

我创建了一个非常简单的Delphi应用程序,演示了这种效果.它由单个表单与一个DBGrid,DataSource,两个ClientDataSet和两个按钮组成.此表单的OnCreate事件处理程序如下所示

procedure TForm1.FormCreate(Sender: TObject);

begin

with ClientDataSet1.FieldDefs do

begin

Clear;

Add('StartOfWeek',ftDate);

Add('Label',ftString,30);

Add('Count',ftInteger);

Add('Active',ftBoolean);

end;

ClientDataSet1.CreateDataSet;

end;

标记为Show ClientDataSet Structure的Button1包含以下OnClick事件处理程序.

procedure TForm1.Button1Click(Sender: TObject);

var

sl: TStringList;

i: Integer;

begin

sl := TStringList.Create;

try

sl.Add('The Structure of ' + ClientDataSet1.Name);

sl.Add('- - - - - - - - - - - - - - - - - ');

for i := 0 to ClientDataSet1.FieldCount - 1 do

sl.Add(ClientDataSet1.Fields[i].FieldName);

ShowMessage(sl.Text);

finally

sl.Free;

end;

end;

要演示移动场效应,请运行此应用程序,然后单击标记为Show ClientDataSet Structure的按钮.你应该看到这样的东西:

The Structure of ClientDataSet1

- - - - - - - - - - - - - - - - -

StartOfWeek

Label

Count

Active

接下来,拖动DBGrid的列以重新排列字段的显示顺序.再次单击显示客户端数据集结构按钮.这次你会看到类似的东西:

The Structure of ClientDataSet1

- - - - - - - - - - - - - - - - -

Label

StartOfWeek

Active

Count

这个例子令人惊奇的是DBGrid的列正被移动,但是对ClientDataSet中的Fields的位置有明显的影响,使得ClientDataSet.Field [0]中的字段位于一个点不一定在那个瞬间.而且,不幸的是,这并不是一个ClientDataSet问题.我使用基于BDE的TTables和基于ADO的AdoTables进行了同样的测试,并得到了相同的效果.

如果您不需要引用显示在DBGrid中的ClientDataSet中的字段,则不必担心此效果.对于其余的人,我可以想到几个解决方案.

最简单的,虽然不是必需的,但避免此问题的最佳方法是防止用户重新排序DBGrid中的字段.这可以通过从DBGrid的Options属性中删除dgResizeColumn标志来完成.虽然这种方法是有效的,但从用户的角度来看,它消除了潜在的有价值的显示选项.此外,删除此标志不仅限制列重新排序,还可以防止列大小调整. (要了解如何限制列重新排序而不删除列调整大小选项,请参阅http://delphi.about.com/od/adptips2005/a/bltip0105_2.htm.)

第二个解决方法是避免基于它们的字面位置引用DataSet的字段(因为这是问题的本质).按顺序,如果您需要参考“计数”字段,请不要使用DataSet.Fields [2].只要知道该字段的名称,就可以使用DataSet.FieldByName(‘Count’).

然而,使用FieldByName有一个相当大的缺点.具体来说,此方法通过遍历DataSet的Fields属性来查找字段,根据字段名称寻找匹配项.由于每次调用FieldByName时都会执行此操作,所以这种方法应该在需要多次引用的情况下避免,例如在导航大型DataSet的循环中.

如果您确实需要重复引用该字段(并且需要大量次数),请考虑使用以下代码片段:

var

CountField: TIntegerField;

Sum: Integer;

begin

Sum := 0;

CountField := TIntegerField(ClientDataSet1.FieldByName('Count'));

ClientDataSet1.DisableControls; //assuming we're attached to a DBGrid

try

ClientDataSet1.First;

while not ClientDataSet1.EOF do

begin

Sum := Sum + CountField.AsInteger;

ClientDataSet1.Next;

end;

finally

ClientDataSet1.EnableControls;

end;

有一个第三个解决方案,但是这只有当您的DataSet是ClientDataSet时才可用,就像我的原始示例中一样.在这些情况下,您可以创建原始ClientDataSet的克隆,并且它将具有原始结构.因此,无论用户对显示ClientDataSets数据的DBGrid做了什么,无论在零位置创建哪个字段,仍将处于该位置.

这在以下代码中演示,该代码与标记为显示克隆的客户端数据结构的按钮的OnClick事件处理程序相关联.

procedure TForm1.Button2Click(Sender: TObject);

var

sl: TStringList;

i: Integer;

CloneClientDataSet: TClientDataSet;

begin

CloneClientDataSet := TClientDataSet.Create(nil);

try

CloneClientDataSet.CloneCursor(ClientDataSet1,True);

sl := TStringList.Create;

try

sl.Add('The Structure of ' + CloneClientDataSet.Name);

sl.Add('- - - - - - - - - - - - - - - - - ');

for i := 0 to CloneClientDataSet.FieldCount - 1 do

sl.Add(CloneClientDataSet.Fields[i].FieldName);

ShowMessage(sl.Text);

finally

sl.Free;

end;

finally

CloneClientDataSet.Free;

end;

end;

如果您运行此项目并单击标记为显示克隆的ClientDataSet结构的按钮,您将始终获得ClientDataSet的真实结构,如下所示

The Structure of ClientDataSet1

- - - - - - - - - - - - - - - - -

StartOfWeek

Label

Count

Active

附录:

重要的是要注意,底层数据的实际结构不受影响.具体来说,如果在更改DBGrid中的列的顺序后,调用ClientDataSet的SaveToFile方法,则保存的结构是原始(true internal)结构.此外,如果将一个ClientDataSet的Data属性复制到另一个ClientDataSet,则目标ClientDataSet还将显示真实的结构(与克隆源ClientDataSet时观察到的结果相似).

类似地,绑定到其他测试数据集(包括TTable和AdoTable)的DBGrids的列顺序的更改实际上不会影响底层表的结构.例如,显示来自client.db示例Paradox表中的数据的TTable不会实际更改该表的结构(也不期望它).

我们可以从这些观察结果得出结论,DataSet本身的内部结构保持不变.因此,我必须假设DataSet的结构存在二次表示.而且,它必须与DataSet相关联(这似乎是过度的,因为DataSet的所有使用都不需要这个),与DBGrid相关联(这使得DBGrid使用此功能更有意义,但不是支持的观察,TField重新排序似乎与DataSet本身一直存在),或者是别的.

另一个替代方案是,效果与TGridDataLink相关联,TGridDataLink是提供多重感知控件(如DBGrids)的数据感知的类.然而,我也倾向于拒绝这个解释,因为这个类与网格相关联,而不是DataSet,因为效果似乎与DataSet类本身一样存在.

这让我回到原来的问题. TDataSet类是TDBGrid的工件还是其他东西?

允许我也在这里强调,我添加了以下评论之一.更重要的是,我的帖子旨在让开发人员意识到,当他们使用DBGrids,其列命令可以被更改时,它们的TField的顺序也可能正在改变.这个工件可以引入间歇性和严重的错误,这可能非常难以识别和修复.而且,不,我不认为这是Delphi的错误.我怀疑一切工作都是为了工作而设计的.只是我们中许多人不知道这种行为正在发生.现在我们知道

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
评论

打赏作者

吴敬欣

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值