[Solved] Very slow assigning a TStringList to a TMemo lazarus / 31-LCL ---------------------------------------------------------------------- trev · 2019-06-15 07:14 I'm assigning a TStringList to a TMemo - there are 4,004 strings of between 10 and 15 characters. On macOS this takes around 33 seconds and "beach balls" the cursor. Using Delphi, the macOS application takes around 2 seconds (I'm porting my application from Delphi to Lazarus). Code: [Select]Memo.Lines := strList; I don't see any way of speeding this up... ---------------------------------------------------------------------- SymbolicFrank · 2019-06-15 07:18 Use TStrings.BeginUpdate and TStrings.EndUpdate. It turns off the display refresh. ---------------------------------------------------------------------- trev · 2019-06-15 07:31 Quote from: SymbolicFrank on June 15, 2019, 09:18:41 amUse TStrings.BeginUpdate and TStrings.EndUpdate. It turns off the display refresh. There is no display. TStringList does not display; it is then assigned to Memo.Lines to avoid the delay of adding lines one by one to the Memo and also to sort the strings before adding. ---------------------------------------------------------------------- Thaddy · 2019-06-15 08:19 Try memo.lines.text := stringlist.text, but plz do use beginupdate/endupdate. That's speed essential. ---------------------------------------------------------------------- howardpc · 2019-06-15 09:01 Quote from: trev on June 15, 2019, 09:31:59 amQuote from: SymbolicFrank on June 15, 2019, 09:18:41 amUse TStrings.BeginUpdate and TStrings.EndUpdate. It turns off the display refresh. There is no display. TStringList does not display; it is then assigned to Memo.Lines to avoid the delay of adding lines one by one to the Memo and also to sort the strings before adding. There is a display. SymbolicFrank was writing about the Memo, not the strList. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var  i: Integer;  period: TTime;  ts: TTimeStamp;begin  strList := TStringList.Create;  try    for i := 0 to 4000 do      strList.Add('This is line number %d',[i]);    period := Time;    Memo1.Lines.BeginUpdate;    Memo1.Lines := strList;    Memo1.Lines.EndUpdate;    ts := DateTimeToTimeStamp(Time - period);  Memo1.Lines.Add('Operation took %d ms',[ts.Time]);    Memo1.SelStart := Length(Memo1.Text);  finally     strList.Free;  end;end; ---------------------------------------------------------------------- trev · 2019-06-15 13:01 I did actually try it with the TMemo (and even the TStringList just in case. Alas, no speed increase at all. See pic (I added your time code along with Begin/End around the Memo StringList assignment). The memo is not actually visible at the time its contents is added (clicking on the tabcontrol to show the memo causes it to read the file, sort the string, and then assign the memo). ---------------------------------------------------------------------- howardpc · 2019-06-15 13:48 If you are convinced you are not timing the process of constructing the strList, only timing the process of assigning the pre-built strList to your memo's Lines, then I think that either the implementation of BeginUpdate/EndUpdate or of Lines.Assign() for TMemo on MacOS is flawed. I know nothing about the underlying widget used on the Mac for a memo, but your result is ridiculous. Copying 4,000 strings from one memory location to another, and then displaying the last 20 or so, should take only a few ms, even on old hardware with long strings (yours are fairly short). ---------------------------------------------------------------------- trev · 2019-06-15 13:57 Definitely convinced: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i           strList.Sort;           period := Time;          BitsMemo.Lines.BeginUpdate;          BitsMemo.Lines := strList;        BitsMemo.Lines.EndUpdate;          ts := DateTimeToTimeStamp(Time - period);          BitsMemo.Lines.Add('Operation took %d ms',[ts.Time]);  The hardware is a 2018 Mac mini with six-core 3.2-4.6GHz i7, so not old or slow I'll go pester the Cocoa widget magician tomorrow. ---------------------------------------------------------------------- marcov · 2019-06-15 14:05 The code looks ok. I'd do a  BitsMemo.Lines.Assign(strList); but that is not the problem I think. Note GUI widgets might not react very well to huge amounts of items, depending on widgetset and implementation. ---------------------------------------------------------------------- ASerge · 2019-06-15 19:41 In Windows the fastes way is Memo.Text := StringList.Text ---------------------------------------------------------------------- trev · 2019-06-15 23:29 Quote from: ASerge on June 15, 2019, 09:41:38 pmIn Windows the fastes way is Memo.Text := StringList.Text Also in macOS  Thankyou! See pic. ---------------------------------------------------------------------- Thaddy · 2019-06-16 04:02 Quote from: ASerge on June 15, 2019, 09:41:38 pmIn Windows the fastes way is Memo.Text := StringList.Text That's what I thought too, but note Marco's remark about assign. Internally the assignment := operator calls Assign, so that may be a little faster... ---------------------------------------------------------------------- trev · 2019-06-16 08:15 For the record: Code: [Select]BitsMemo.Lines.Assign(strList); Operation took 28067 ms ---------------------------------------------------------------------- Thaddy · 2019-06-16 08:45 That is unexpected? Anyway in that case my first hunch was right. ---------------------------------------------------------------------- Remy Lebeau · 2019-06-18 20:43 Quote from: howardpc on June 15, 2019, 11:01:48 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Memo1.Lines.BeginUpdate;Memo1.Lines := strList;Memo1.Lines.EndUpdate; I would expect the Lines property setter to call (Begin|End)Update() internally.  It does in Delphi (which simply calls FLines.Assign(), and then TStrings.Assign() handles the updating). Quote from: howardpc on June 15, 2019, 11:01:48 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Memo1.SelStart := Length(Memo1.Text); I would use the TMemo.GetTextLen() method instead of querying the Length of the Text property.  That way, it avoids having to actually read the full Text into memory first. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Memo1.SelStart := Memo1.GetTextLen;