使用大量线路时,TMemo非常慢

WeG*_*ars 4 delphi delphi-xe7

我在TMemo中有100000行.我想做的事情如下:

 for i:= 0 to Memo.Lines.Count-1 do
  Memo.Lines[i]:= SomeTrim(Memo.Lines[i]);
Run Code Online (Sandbox Code Playgroud)

但速度是每秒0.5线!!

添加BeginUpdate/EndUpdate后,我没有看到任何速度提升.

 Memo.Lines.BeginUpdate;
 for i:= 0 to Memo.Lines.Count-1 do
  Memo.Lines[i]:= SomeTrim(Memo.Lines[i]);
 Memo.Lines.EndUpdate;
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么BeginUpdate/EndUpdate无济于事?

Uwe*_*abe 10

TStrings.BeginUpdate/EndUpdate只会禁止OnChangingOnChanged事件.它对内容本身更改的内部处理没有影响.

TMemo.Lines实现通过TMemoStrings它将文本内容存储在Window控件本身中.因此BeginUpdate/EndUpdate在这里毫无用处.

你可能会通过使用本地获得更好的效果TStringList实例,并使用Text属性来复制数据TMemoTStringList和背部.该Text属性是TMemo一次访问整个内容的最有效方式.

  lst := TStringList.Create;
  try
    lst.Text := Memo1.Lines.Text;
    for I := 0 to lst.Count - 1 do begin
      lst[I] := SomeTrim(lst[I]);
    end;
    Memo1.Lines.Text := lst.Text;
  finally
    lst.Free;
  end;
Run Code Online (Sandbox Code Playgroud)

注意:有些评论提到在从备忘录复制内容时使用Assign而不是Text属性:Assign在这种情况下,由于内部优化Text属性,速度明显变慢TMemoLines.此属性的Getter和Setter使用单个WM_GETTEXT/WM_SETTEXT消息直接访问Windows控件,同时Assign每行使用一个EM_GETLINE消息进行读取,每行使用EM_LINEINDEX,EM_SETSEL,EM_LINELENGTH和EM_REPLACESEL序列进行写入.一个简单的定时测试表明上述代码需要大约600毫秒,而用调用替换Text分配Assign需要超过11秒!

  • 我对此很清楚.我指的是将Memo内容复制到StringList然后再返回.你的答案说`Text`属性是"最有效"的方法,但这甚至不是真的,特别是对于100000行.`Text` getter执行2遍扫描以分配和复制内存,然后`Text` setter解析输入以执行大量分配.另一方面,`Assign()`执行的分配要少得多,并使用1遍扫描.为自己配置文件,`Assign()`比`Text`更有效 (9认同)
  • 使用`Assign()`方法代替`Text`属性:`lst.Assign(Memo1.Lines); ... Memo1.Lines.Assign(lst);`由于这些行已经是分开的,只需按原样复制它们,不要将它们连接起来只是为了重新解析它们,这是浪费内存和处理 (5认同)
  • @ RemyLebeau,TStrings.Text属性使用虚拟GetTextStr和SetTextStr方法,这些方法在TMemoLines中被覆盖.这些实现通过单个WM_GETTTEXT或WM_SETTEXT消息调用访问控件文本内容.我测试了它并使用Text更快(如18x). (5认同)