我有一个内存中的数据集,通过一些数据源连接到TDBGrid。问题是,每当用户在数字字段中输入减号并按ENTER键或导航到另一条记录时,就会触发AV (验证错误)。我无法从TDBGrid或TClientDataSet (OnEditError、OnPostError)捕获AV。
我是不是做错了什么。如果没有,有谁有办法解决这个问题吗?
使用XE2企业版,第4次更新;最新的MIDAS.DLL;目标平台: Win64。
==============================================================================
请尝试以下操作:
1-创建一个新的VCL应用程序/表单,并在表单中添加对象: TClientDataSet、TDBGrid和TDataSource。ClientDataSet未连接到任何数据库(在内存中)
2-向Table1 ( TClientDataSet)添加永久数字字段。
3-链接上述三个对象。持久字段的列应该出现在TDBGrid上。
4-在主窗体的OnShow方法中添加以下行:
表1.Active := False;
表1.CreateDataSet;
表1. :=真;
5-运行您的程序并在数字字段列中键入减号,然后按Enter键。
检查AV,然后尝试向Table1添加OnEditError和/或OnPostError事件处理程序以捕获AV。您不能中止帖子。这意味着,AV将会发生,您只能使用Application.OnException处理程序捕获它。这可不好。假设您的应用程序包含许多表单和例程,而不是更高的级别,那么您应该能够在您的程序运行的级别上执行某些操作。
我希望我的问题说得更清楚了。
发布于 2012-06-07 02:31:00
正如Ken所说,如果没有示例代码,很难为您提供帮助。因此,我不能直接回答您的问题,但通过一些提示,您也许能够自己解决这个问题。所以我要试着教你钓鱼。;)
我对Delphi3和Delphi6中的TClientDataSet有相当多的经验,我怀疑事情有那么大的变化。另外,我将更多地关注一些技术,让您在正确的方向上起步。
首先,确保使用Debug DCU进行编译,这样就可以在VCL代码中获得断点。不要害怕阅读并逐步了解这些代码-这是一个很好的学习方法。此外,您还可以看到Borland/CodeGear/Embarcadero的所有丑陋的错误。
我假设你已经启用了Stop on Exceptions (因此你知道你特别得到了AV错误)。
做你的测试。当你得到你的AV时,你可能会用DbClient.pas (或者一个较低级别的单位)出来。
遍历调用堆栈,查找位于try..except块的try部分中的位置,该位置可以接受异常,也可以短路到另一个处理程序,然后再接受它。
注意: 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;侧评:仅仅因为Borland做到了这一点,并不意味着这是一种好的实践。你和其他许多人已经并将被这件事烧毁。
一旦你发现了这一点,你就走到了一半。现在你知道为什么你没有被告知AV了。
现在,在构成调用堆栈一部分的代码中的某个地方,将会提供一个线索,告诉您应该如何处理错误。您还可以在VCL代码中稍早放置一个断点,这样您就可以单步执行来查看导致异常的事件序列。由于您特别提到了AV (访问冲突),因此请查找引用nil的对象。
可能导致该问题的一个示例是来自D5 DbClient.pas的以下代码片段
FOnReconcileError(DataSet, E, UpdateKind, Action);
finally
E.Free;
end;
except
Application.HandleException(Self);
Action := raAbort;
end;从上面可以看出,某些情况要求您实现一个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;在调用堆栈的较高位置,您将获得以下方法,该方法提示如何解决问题。
procedure TField.SetEditText(const Value: string);
begin
if Assigned(FOnSetText) then FOnSetText(Self, Value) else SetText(Value);
end;此外,如果按照调用堆栈一直到KeyPress,您会注意到根本不涉及数据集或网格代码。
您尝试处理OnPost中的error错误失败的原因是您无法尝试发布记录。您将收到一个字段验证错误,而处理该错误的位置是在字段上。
返回到如何解决错误的提示-您必须为字段实现一个OnSetText事件。
但是,,我建议你不要这么做。开箱即用的行为是完全可以接受的!用户收到一条错误消息,解释他们做错了什么,然后他们有机会修复它并重试。如果他们改变了主意,他们可以按Escape并取消编辑。
https://stackoverflow.com/questions/10917671
复制相似问题