我如何使用 onchange 事件创建 Tstrings?

how do i create Tstrings with onchange event?

我知道如何制作 Tstringlist onchange 事件,但是 Tstrings 呢?我不想使用像 tmemo 之类的 VCL。我可以这样做吗?是否可以在 tstrings 上进行此事件并在其更改时执行某些操作?

我试图做这样的事情但是遇到了访问冲突

//on form show event
   stringlist:= TStringList.Create;
  stringlist.OnChange := HandleStringListChange;
//implantation 
    procedure TChatFo.HandleStringListChange(Sender: tObject);
    begin
    if stringlist.Text <> '' then
    ProcessCommands(stringlist.Text);
    stringlist.Clear;
    end;

异常消息

Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x6d40c92c: read of address 0x00000150'.

Project Project1.exe raised exception class EStringListError with message 'List index out of bounds (5)'.

Project Project1.exe raised exception class EStringListError with message 'List index out of bounds (5)'.


这个 tstringlist 应该用作命令标识符我用我的线程创建它

例如

类型

  TReadingThread = class(TThread)
  protected
    FConnection  : TIdTCPConnection;
    FLogResult   : TStrings;
    procedure Execute; override;
  public
    constructor Create(AConn: TIdTCPConnection; ALogResult: TStrings); reintroduce;
  end;

ListeningThread := TReadingThread.Create( TCPClient, stringlist);



constructor TReadingThread.Create(AConn: TIdTCPConnection; ALogResult: TStrings);
begin
  FConnection := AConn;
  FLogResult  := ALogResult;
  inherited Create(False);
end;


procedure TReadingThread.Execute;
Var
  strData : String;
begin
  while not Terminated do
  begin
    try
      strData := FConnection.IOHandler.ReadLn;
      if strData <> '' then
      begin
        FLogResult.Add( strData );
      end;
    except
      on E: Exception do
      begin
        FConnection.Disconnect(False);
        if FConnection.IOHandler <> nil
          then FConnection.IOHandler.InputBuffer.Clear;
        Break;
      end;
    end;
    Sleep(10);
  end; // While
end;

如果我使用 Tmemo 没有错误或异常发生。

TStrings 是 class 的抽象,TStringList 的祖先。您可以创建 TStringList 的实例并将其用作 TStrings.

您的错误的可能解释是您正在修改其 OnChange 事件处理程序中的列表。那是根本不允许的。 OnChange 处理程序不得改变对象的状态。

发生的事情是您有一些我们看不到的其他代码修改了列表,也许是在一个循环中。当它修改列表时,您的事件处理程序会清除列表,然后调用代码已从其下方拉出地毯。

当然,由于您没有显示完整的代码,我不得不在这里猜测。也许具体情况有所不同,但这似乎是您问题的根源。

您需要找到另一种方法来解决您的问题。根据现有信息,我们无法建议如何做到这一点。


查看您更新后的代码,根本不需要字符串列表。完全删除它。相反,你在哪里:

FLogResult.Add( strData );

这样做:

ProcessCommands( strData );

我们都在摸黑,因为你没有提供所有相关代码。也就是说,你提供的信息有很多问题,我可以提供建议帮你解决。

调试 101

运行 你的代码通过了IDE。当您遇到异常时,调试器会在导致异常的行处停止。
这通常是找出问题所在的最重要步骤。您可以访问此信息。 运行 您的程序并仔细查看引发错误的行。您可能已经知道是什么导致了错误。如果没有,可以应用其他基本技术来获取更多信息:

  • 获取错误行和其他关闭行上的对象和变量的值。您可以将鼠标光标悬停以获取工具提示,或按 Ctrl + F7
  • 您可以通过双击调用堆栈中的前一行来检查 调用堆栈 导致错误的行。
  • 在错误前一行打断点,重新运行应用。调试器将在该行停止并让您有机会检查值,如前所述,但 before 错误发生。

寻求帮助101

当您向人们提供所有相关信息时,从他们那里获得帮助会更加有效。首先,发生访问冲突的代码行将非常有用....告诉我们!

给我们真实代码.
说 "I tried to do something like this" 不是特别有用。请完全复制并粘贴您尝试过的内容。如果您的代码不同,您的错误可能不再存在。

访问违规

在以下情况下您会遇到访问冲突:

  • 您忘记创建要使用的对象或没有将其分配给适当的变量。
  • 您创建了该对象,但在尝试再次使用它之前已经对它进行了 Destroy 编辑或 Free 编辑。
  • 您更改了引用该对象的变量。
  • 您执行了从一种类型到不兼容类型的 'hard-cast'(或未经检查的类型转换)。
  • 以上是基础知识。有一些变体和一些特殊的边缘情况,但这些占了绝大多数错误。

所以使用上面的内容,这就是您需要检查的内容。如果您复制-粘贴了更多的代码,我们也许可以看到您做错了什么。

注意:一种暗中射击的可能性是你在错误的地方破坏了你的字符串列表。也许备忘录之所以有效,是因为作为一个组件放在表单上,​​您不会试图破坏它。

堆栈溢出

让我们检查一下在添加字符串时您的 OnChange 事件中会发生什么:

  • 事件触发。
  • Text不为空
  • 所以你打电话给ProcessCommands
  • 然后您调用 Clear
  • Clear结束,Changed再次调用
  • 这会再次触发您的事件。
  • 这次Text是空的,所以你不会调用ProcessCommands
  • 但是您确实再次尝试 Clear 字符串列表...
  • 这可能永远持续下去;好吧,至少直到调用堆栈 运行 超出 space 并且出现堆栈溢出错误。

钟声保存

你没有得到堆栈溢出的唯一原因是如果字符串列表为空,Clear 不做任何事情:

procedure TStringList.Clear;
begin
  if FCount <> 0 then //You're lucky these 2 lines stop your stack-overflow
  begin
    ...
    FCount := 0;      //You're lucky these 2 lines stop your stack-overflow
    SetCapacity(0);
    Changed;
  end;
end;

我建议你重新考虑如何解决你的问题,因为导致无意递归的代码会让你的生活变得困难。

使用线程

在尝试使用线程之前,您确实需要掌握编程基础知识。多线程编程带来了巨大的复杂性。

我已经看出一个潜在错误的可能性很大。 (虽然这取决于你在里面做什么ProcessCommands。)

  • 您在线程的上下文中修改字符串列表。
  • 这意味着您的 OnChange 事件处理程序也在线程的上下文中触发。 (它在表单上实现的事实无关紧要。
  • 如果您的 ProcessCommands 方法执行任何需要它在主线程上运行的操作,您将 遇到问题。

作为最后的考虑,我注意到相当多的初学者完全忽略了启动线程的代码可以在 线程完成之前完成这一点。例如。 (回到关于访问冲突的主题。):如果您在创建线程后不久就销毁字符串列表,那么当它之前拥有的对象突然消失时,您的线程可能会突然引发访问冲突。