Exp*_*nce 4 delphi tclientdataset delphi-xe2
我有一个内存数据集通过一些数据源附加到TDBGrid.问题是,只要用户在数字字段中输入减号并按ENTER或导航到另一个记录,就会触发AV(验证错误).我无法从TDBGrid和TClientDataSet(OnEditError,OnPostError)捕获AV.
我在这里做错了什么.如果没有,有人有解决方法吗?
使用Delphi XE2 Enterprise,第4次更新; 最新的MIDAS.DLL; 目标平台:Win64.
================================================== ============================
请尝试以下方法:
1-创建一个新的VCL应用程序/表单,并将对象:TClientDataSet,TDBGrid和TDataSource添加到表单中.ClientDataSet未附加到任何数据库(内存中)
2-向Table1(TClientDataSet)添加持久数字字段.
3-链接上述三个对象.持久字段的列应出现在TDBGrid上.
4-在主窗体的OnShow方法中添加以下行:
Table1.Active:= False;
Table1.CreateDataSet;
Table1.Active:= True;
5-运行程序并在数字字段列中键入减号,然后按Enter键.
检查AV,然后尝试向Table1添加OnEditError和/或OnPostError事件处理程序以捕获AV.你不能中止这个帖子.意思是,AV会发生,你只能使用Application.OnException处理程序捕获它.这不好.您应该能够在程序运行的级别执行某些操作,假设您的应用程序包含许多表单和例程,而不是更高级别.
我希望我的问题更清楚.
正如Ken所说,如果没有示例代码,很难帮助您.因此,我无法直接回答您的问题,但只需几点,您就可以自己解决问题.所以我打算教你钓鱼.;)
我对Delphi 3和6中的TClientDataSet有相当多的经验.我怀疑事情已经发生了很大变化.此外,我将更多地关注技术,以便在正确的方向上启动你.
首先,确保使用Debug DCU进行编译,以便在VCL代码中获得断点.不要害怕阅读并逐步完成代码 - 这是一种很好的学习方式.另外,你可以看到Borland/CodeGear/Embarcadero在其丑陋的丑陋中的错误.
我假设你已经启用了Exceptions Stop(因此你知道你为什么特意得到AV错误).
做你的考试.当你获得AV时,你可能会出现在DbClient.pas(或者可能是较低级别的单位之一)中.
通过调用堆栈寻找一个地方,在那里你在try..except块的try部分内,它可以吞下Exception或者短路到另一个处理程序,然后吞下它.
注意:DbClient.pas充斥着以下不良代码的大量实例:
except //swallowing or squashing exceptions is
end; //very dangerous and should be avoided.
except
//short-circuiting to Application.HandleException (usually informs the user)
//but is not much better. The point is the rest of the program up the
//call-stack remains blissfully unaware that something went wrong.
Application.HandleException(Self);
Action := raAbort;
end;
Run Code Online (Sandbox Code Playgroud)
旁评:只是因为Borland做到了,并不意味着这是一个好习惯.你和许多其他人已经并将被此焚烧.
一旦你找到了,你就到了中途.你现在知道为什么你没有被告知AV.
现在,构成该调用堆栈一部分的代码中的某个位置将是您预期如何处理错误的线索.您还可以在VCL代码中稍早放置一个断点,这样您就可以单步执行以查看导致异常的事件序列.由于您特别提到了AV(访问冲突),因此请查找引用nil的对象.
可能导致问题的一个例子是D5 DbClient.pas的以下代码片段
FOnReconcileError(DataSet, E, UpdateKind, Action);
finally
E.Free;
end;
except
Application.HandleException(Self);
Action := raAbort;
end;
Run Code Online (Sandbox Code Playgroud)
从上面可以看出,某些情况需要您实现OnReconcileError事件处理程序.如果没有它,dll将不会被回调到上面的代码片段中,并且许多错误会在地毯下悄悄地被踢,让你挠头.
我对TClientDataSet的体验是,为了"正确"使用它,你需要做一些额外的事情.这在文档中并不是特别明显.虽然一旦你弄清楚了你应该做的所有零碎碎片,但是如何做到这些的例子要好一些.
不幸的是,对于所有这些事情,我的记忆有点模糊.所以这是一个verrry粗略的指南,可能缺少了不少.
根据问题中的其他信息并使用上述技术,您将从以下方法中获取EDatabaseError.
procedure TIntegerField.SetAsString(const Value: string);
var
E: Integer;
L: Longint;
begin
if Value = '' then Clear else
begin
Val(Value, L, E);
if E <> 0 then DatabaseErrorFmt(SInvalidIntegerValue, [Value, DisplayName]);
SetAsInteger(L);
end;
end;
Run Code Online (Sandbox Code Playgroud)
在调用堆栈的上方,您将获得以下方法,该方法提示如何解决问题.
procedure TField.SetEditText(const Value: string);
begin
if Assigned(FOnSetText) then FOnSetText(Self, Value) else SetText(Value);
end;
Run Code Online (Sandbox Code Playgroud)
此外,如果您一直跟着调用堆栈一直到KeyPress,您会注意到根本没有涉及NO数据集或网格代码.
您尝试在OnPost错误中处理错误的原因不起作用的原因是您没有尝试发布您的记录.您收到了字段验证错误,并且该字段位于该字段上.
回到提示如何解决错误 - 您必须为该字段实现OnSetText事件.
但是,我建议不要这样做.开箱即用的行为是完全可以接受的!用户会收到一条错误消息,说明他们做错了什么,他们有机会修复它并再试一次.如果他们改变主意,他们可以点击Escape并取消编辑.