我正在处理具有两个列表框的应用程序。我使用值加载两个列表框,当我继续单击列表框中的项目时,我在调试时收到以下错误。
运行exe会导致应用程序关闭。有时我会收到“访问冲突”消息。
那么我应该怎样做才能从我的应用程序中消除这个错误?
修改
...
主窗体具有刷新所有控件的计时器 timer_RefreshCOntrol(intervali 1)。
修改editBox_one时的值(值) 这个函数叫做
Procedure TStringSetting.SetValue (const AValue : String);
Begin
...
If FValueControl <> Nil then
Begin
FValueControl.OnChange := VoidNotifyEvent;
FValueControl.Text := NewValue;
FValueControl.OnChange := EditChange; //<--here the stackoverflow error comes....
end;
end;
Procedure EditChange (Sender: TObject);
Begin
Value := FValueControl.Text;
If Not EditIsValid then FValueControl.Font.Color := clRed
else If Dirty then FValueControl.Font.Color := clBlue
else FValueControl.Font.Color := clWindowText;
If @OldCustomEditChange <> Nil then OldCustomEditChange(Sender);
end;`
the EditChange (Sender: TObject); <--keeps geting called and the stackoverflow error comes
EditChange
被分配到FormCreate
EDIT2
我不是原始的开发人员。我刚回来处理代码,无法进行重大重构。
编辑3 调用堆栈值但是什么是“???”
编辑4
经过@Cosmin Prund和@david 之后
我得到了无限呼叫开始的地方
Procedure TFloatSetting.EditChange (Sender: TObject);
Begin
SkipNextOnChange := True;
Inherited EditChange(Sender);
IfValidThenStore(FValueControl.Text);
Inherited EditChange(Sender); {<-------This is where it start}
end;
Procedure TStringSetting.EditChange (Sender: TObject);
Begin
Value := FValueControl.Text;
If Not EditIsValid then FValueControl.Font.Color := clRed
else If Dirty then FValueControl.Font.Color := clBlue
else FValueControl.Font.Color := clWindowText;
If @OldCustomEditChange <> Nil then OldCustomEditChange(Sender); {<---this keeps calling Procedure TFloatSetting.EditChange (Sender: TObject);}
end;
答案 0 :(得分:9)
基于发布的调用堆栈,很明显错误发生的原因是:TStringSetting.EditChange
触发TFloatSetting.EditChange
,然后触发TStringSetting.EditChange
。循环继续这样,直到所有堆栈空间都耗尽。
以下是有关可能发生这种情况的原因的一些提示,以及有关如何调试和修复它的提示:
OnChange
以编程方式更改时,可能涉及的控件会触发Value
事件处理程序。如果两个编辑器应该以两种格式显示相同的数据,并且您使用相应的OnChange
事件处理程序来保持它们同步,则可能是原因。调试方法:
paulsm4
建议的断点解决方案。如果每次调用其中一个OnChange
处理程序时都发生堆栈溢出,则此解决方案很容易工作。如果您正在使用的控件在以编程方式更改值时触发OnChange
事件处理程序,则应使您的事件处理程序不可重入:这将确保无限递归循环。当代码更改属性时,我几乎总是假设控件触发OnChange
或等效事件,并始终使用以下内容保护自己不被重新输入:
// Somewhere in the private section of your form's class:
FProcessingEventHandler: Boolean;
// This goes in your event handler
procedure TYourForm.EventHandler(Sender:TObject);
begin
if FProcessingEventHandler then Exit; // makes code non-reentrant
FProcessingEventHandler := True;
try
// old code goes here ...
finally FProcessingEventHandler := False;
end;
end;
答案 1 :(得分:3)
您向EditChange
报告一个非终止递归调用序列。查看EditChange
的代码,有两个递归调用的候选者:
OldCustomEditChange
等于EditChange
,或调用的函数又会调用EditChange
。FValueControl.Font
来响应EditChange
更改的事件处理程序。这些是EditChange
中代码调用自身的唯一机会。
很容易看出这两种可能性如何导致非终止递归函数调用并最终导致堆栈溢出。在这两个候选人中,我的赌注是1号。我会仔细研究OldCustomEditChange
被召唤时会发生什么。
要调试这种性质的堆栈溢出,只需打开调用堆栈窗口并查看长序列调用。您通常会看到一个模式,其中一个函数可能通过一个或多个中间函数调用自身。
答案 2 :(得分:3)
建议:
在EditChange和OldCustomEditChange中设置断点,以查看谁在调用它们。每次调用。显然,只有 EditChange才能永远调用OldCustomEditChange。
查看.dfm以确保EditChange仅分配给一个事件(而不是多个事件),并且根本不分配OldCustomEditChange。