Sunday, April 4, 2021

TMemoLines and FileStream

Saving TMemoLines to a Logfile

Some Discoveries About Linebreaks

Summary

A small sample program illustrating this is available for download or cloning at GitHub:

SavingMemoLines

While attempting to save multiple groups of lines from a TMemo component, each new group appended to a log file, I expected each new group of lines saved to begin on a new line. After all, TStrings has a TrailingLineBreak option that should ensure that each group of lines ends with an appropriate Linebreak.

Instead, each new group of lines immediately followed the preceding group without any sort of delimiter, Linebreak or otherwise.

A little examination revealed that the TrailingLinebreak was not being inserted. I set out to discover why. (I was not successful in my search!)

What I Tried to Do

Sometimes during development I use a TMemo to record events, either system generated or manually entered by me. Then, I'd like to save those memo lines to a logfile for future reference. I have a small component that does all of this and also has a display option that will display the current log file in a separate window.

What I wanted to do was:

  • Assume we have a TMemo object available
  • Assume we have a full path and file name available to receive the TMemoLines content.
  • Assume we have a procedure that appends the TMemoLines to the end of the log file.
  • TStrings has a TrailingLineBreak option that when True (the default) should ensure that each series of lines ends with a line break.
  • Because each series of lines should end with a line break, when multiple insertions of lines takes place, each new group of lines should begin at the left margin.

It looks something like this:

What Actually Happened

What actually happens is for multiple insertions of lines from the memo, the first line of insertions following the first begins immediately following the end of the first insertion, thus running the two lines together.

One way to avoid this is to ensure that lines in the memo always end with a trailing line break. This means that if you're entering lines manually, you must remember to insert the trailing line break yourself. This might be acceptable unless the lines you're saving are generated by software that doesn't include the trailing line break. Overall, this is not a completely reliable solution and one that seems kind of specious given the fact that TStrings includes a property especially for that purpose.

Why It Happened

I wasn't able to actually pinpoint the reason by examining the Delphi VCL source code. It seems to be related to the fact that the TStrings of the TMemo are really TMemoLines, descended from TStrings and in the process the Text property is overridden to a method that does not examine the TrailingLinebreak option.

If somebody can figure out what happened to the Text property, I'd be interested to hear the explanation.

My Workaround

My workaround is fairly simple.

  • Set up a TStringList as a work area
  • Use MyStringList.Assign(TMemo.Lines) to place the TMemolines in the work StringList.
  • Continue from there using the work StringList, which results in the Text property honoring the TrailingLineBreak option.

Conclusion

Still kind of aggravating, but the workaround is easy to accomplish and given the infrequent use of most log files doesn't result in a lot of unnecessary overhead.

And so, on to the next problem.

FireMonkey String Grid Responsive Columns

FireMonkey String Grid Responsive Columns Code to Cause Column Widths to Change When String Grids Are Resized Overview I have a FireMonke...