1

我正在处理具有两个列表框的应用程序。我用值加载了两个列表框,当我继续单击列表框中的项目时,调试时出现以下错误。

在此处输入图像描述

运行 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

编辑2

我不是最初的开发人员。我有时只是处理代码,不可能进行重大重构。

编辑 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;
4

3 回答 3

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;
于 2012-03-08T08:29:58.120 回答
3

建议:

  1. 在 EditChange 和 OldCustomEditChange 中设置断点以查看谁在调用它们。每次调用。显然,只有EditChange 应该调用 OldCustomEditChange

  2. 查看您的 .dfm 以确保仅将 EditChange 分配给一个事件(而不是多个事件),并且根本没有分配 OldCustomEditChange。

于 2012-03-08T07:46:01.300 回答
3

您向 报告非终止递归调用序列EditChange。查看EditChange有两个候选递归调用的代码:

  1. OldCustomEditChange等于EditChange,或调用一个函数,而该函数又调用EditChange.
  2. FValueControl.Font通过调用响应更改的事件处理程序EditChange

这些是代码EditChange调用自身的唯一机会。

很容易看出这两种可能性如何导致非终止递归函数调用并最终导致堆栈溢出。OldCustomEditChange在这两位候选人中,我的赌注是第一名。我会仔细研究被叫时会发生什么。

要调试这种性质的堆栈溢出,只需打开调用堆栈窗口并查看一长串调用。您通常会看到一个模式,其中一个函数调用自身,可能通过一个或多个中间函数。

于 2012-03-08T07:21:13.523 回答