1

2つのリストボックスを持つアプリケーションで作業しています.2つのリストボックスに値をロードし、リストボックスの項目をクリックし続けると、デバッグ中に次のエラーが発生します。

ここに画像の説明を入力してください

exeを実行すると、アプリケーションが閉じます。「アクセス違反」メッセージが表示されることがあります。

それで、私のアプリケーションからこのエラーを取り除くために私は何をすべきですか?

編集

..

メインフォームには、すべてのコントロールtimer_RefreshCOntrol(間隔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

@CosminPrundと@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たときにイベントハンドラーをトリガーします。Value2つのエディターが同じデータを2つの形式で表示することになっていて、それぞれのOnChangeイベントハンドラーを使用して同期を維持している場合は、これが原因である可能性があります。
  • たぶん、あるイベントハンドラーを他のイベントハンドラーから直接呼び出しているのかもしれません。

これをデバッグする方法:

  • によって提案されているように、最初にブレークポイントソリューションを試す必要がありますpaulsm4。ハンドラーの1つが呼び出されるたびにスタックオーバーフローが発生する場合OnChange、このソリューションは簡単に機能します。
  • イベントハンドラーの1つのコードをコメントアウトします。プログラムを実行すると、エラーは表示されなくなります。少量の(しかし論理的な)コードのコメントを外し、テストして繰り返します。エラーが再び表示されたら、エラーの原因となっている回線に資金を提供していることがわかります。自分で理解できない場合は、質問を編集し、コードを追加して、問題が発生していることがわかった行にマークを付けます。

値がプログラムで変更されたときに使用しているコントロールが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

非終了の再帰呼び出しシーケンスをに報告しEditChangeます。のコードを見るとEditChange、再帰呼び出しの候補が2つあります。

  1. OldCustomEditChangeに等しいEditChange、またはを呼び出す関数を呼び出すEditChange
  2. FValueControl.Fontを呼び出すことにより、への変更に応答するイベントハンドラーEditChange

これらは、コードがEditChangeそれ自体を呼び出す唯一の機会です。

これらの可能性の両方が、非終了の再帰関数呼び出しにつながり、最終的にはスタックオーバーフローにつながることは簡単にわかります。2つの候補のうち、私の賭けは1番ですOldCustomEditChange。呼び出されたときに何が起こるかを注意深く調べます。

この性質のスタックオーバーフローをデバッグするには、コールスタックウィンドウを開いて、呼び出しの長いシーケンスを確認するだけです。通常、1つ以上の中間関数を介して、1つの関数がそれ自体を呼び出すパターンが表示されます。

于 2012-03-08T07:21:13.523 に答える
3

提案:

  1. EditChangeとOldCustomEditChangeにブレークポイントを設定して、誰がそれらを呼び出しているかを確認します。各呼び出し。明らかに、 EditChangeのみがOldCustomEditChangeを呼び出す必要あります。

  2. .dfmを調べて、EditChangeが(複数のイベントではなく)1つのイベントにのみ割り当てられ、OldCustomEditChangeがまったく割り当てられていないことを確認します。

于 2012-03-08T07:46:01.300 に答える