how do i create Tstrings with onchange event?

-1

i know how to make Tstringlist onchange event , but what about Tstrings ? i dont want to use VCL like tmemo or something . can i do that ? is it possible to have this event on tstrings and do something when its changed ?

i tried to do something like this but got access violation

//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;

exception messages

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)'.


this tstringlist should work as command identifier i creat it with my thread

as example

type

  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;

if i use Tmemo no errors or exception happened.

delphi
delphi-xe7
asked on Stack Overflow Jul 24, 2015 by MartinLoanel • edited Jul 24, 2015 by MartinLoanel

3 Answers

2

We're all shooting in the dark here because you haven't provided all the relevant code. That said, the information you have provided has a lot of problems, and I can offer advice to help you solve it.

Debugging 101

Run your code through the IDE. When you get your exception, the debugger stops at the line that caused the exception.
This is usually the most important step in figuring out what went wrong. You have access to this information. Run your program and carefully look at the line that raised the error. You might be able to already figure what caused the error. If not, a other basic techniques can be applied to get more information:

  • Get values of objects and variables on the error line and other close lines. You can hover your mouse cursor to get tool-tips, or press Ctrl + F7.
  • You can examine the call stack of lines leading to the one that caused the error by double-clicking the previous line in the call-stack.
  • Put a breakpoint on the line before the error and re-run the app. The debugger will stop on that line and give you a chance to check values as explained earlier, but before the error happens.

Asking for help 101

Getting help from people is much more effective when you give them all the relevant information. For a start, the line of code where the access violation occurs would be extremely useful.... Tell us!

Give us real code.
Saying "I tried to do something like this" is not particularly useful. Please copy and paste exactly what you tried. If your code is different, your mistake might no longer be there.

Access Violations

You get an access violation in the following situations:

  • You forgot to create the object you want to use or didn't assign it to the appropriate variable.
  • You created the object but Destroyed or Freed it already before trying to use it again.
  • You changed the variable that was referencing the object.
  • You performed a 'hard-cast' (or unchecked typecast) from one type to an incompatible type.
  • The above are the basics. There some variations, and a few special edge cases, but these account for the vast majority of mistakes.

So using the above, that's what you need to check. If you had copy-pasted more of your code, we might be able to see what you did wrong.

NOTE: One shot-in-the-dark possibility is that you are destroying your string list in the wrong place. And perhaps the memo works because as a component dropped on the form, you're not trying to destroy it.

Stack overflow

Let's examine what happens in your OnChange event when for example a string is added:

  • The event fires.
  • Text is not empty.
  • So you call ProcessCommands
  • You then call Clear
  • The the end of Clear, Changed is called again.
  • Which fires your event again.
  • This time Text is empty, so you won't call ProcessCommands
  • But you do try to Clear the string list again...
  • This could go on forever; well at least until the call-stack runs out of space and you get a stack-overflow error.

Saved by the bell

The only reason you don't get a stack overflow is because Clear doesn't do anything if the string list is empty:

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;

I suggest you rethink how to solve you problem because code that leads to unintentional recursion is going to make your life difficult.

Working with threads

You really need to get a handle on the basics of programming before trying to work with threads. Multi-threaded programming throws in a huge amount of complexity.

I can already see a huge possibility of one potential mistake. (Though it depends what you're doing inside ProcessCommands.)

  • You modify your string list in the context of a thread.
  • This means your OnChange event handler also fires in the context of the thread. (The fact it's implemented on the form is irrelevant.)
  • If your ProcessCommands method does anything that requires it to operate on the main thread, you're going to encounter problems.

As a final consideration, I've noted quite a few beginner programmers completely miss the point that code starting a thread can finish before the thread does. E.g. (Going back to the topic on Access Violations.): If you're destroying your string list soon after creating your thread, your thread could suddenly throw an access violation when the object it had earlier is suddenly gone.

answered on Stack Overflow Jul 24, 2015 by Disillusioned
1

The likely explanation for your error is that you are modifying the list in its OnChange event handler. That is simply not allowed. An OnChange handler must not mutate the state of the object.

What is happening is that you have some other code, that we cannot see, that modifies the list, perhaps in a loop. As it modifies the list your event handler clears the list and then the calling code has had the rug pulled from underneath it.

Of course, I'm having to guess here since you did not show complete code. Perhaps the specifics vary somewhat but it seems likely that this is the root of your problem.

You'll need to find another way to solve your problem. With the information available we cannot suggest how to do that.


Looking at your updated code, there's no need for a string list at all. Remove it completely. Instead, where you do:

FLogResult.Add( strData );

do this:

ProcessCommands( strData );
answered on Stack Overflow Jul 24, 2015 by David Heffernan • edited Jul 24, 2015 by David Heffernan
0

TStrings is an abstract class, ancestor of TStringList. You can create an instance of TStringList and use it as a TStrings.

answered on Stack Overflow Jul 24, 2015 by AlexSC • edited Jul 24, 2015 by David Heffernan

User contributions licensed under CC BY-SA 3.0