2017-10-28 62 views
4

我在TMemo中有100000行。我想做類似的事情:TMemo在處理大量行時非常緩慢

for i:= 0 to Memo.Lines.Count-1 do 
    Memo.Lines[i]:= SomeTrim(Memo.Lines[i]); 

但速度是每秒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; 

我的問題是爲什麼BeginUpdate/EndUpdate不會幫助?

+3

不好的用戶會滾動這樣的備忘錄。 – Victoria

+0

PS:目前的解決方案是將行分配給TStringList,處理它們並將它們放回備忘錄。但我仍然好奇爲什麼BeginUpdate不起作用。 – Ampere

+0

@維多利亞 - 用戶將把那些線放在那裏。通常情況下,我預計在100行以下。我想測試看看100000會發生什麼情況。這就是發生了什麼事情。 – Ampere

回答

10

TStrings.BeginUpdate/EndUpdate只會禁止OnChangingOnChanged事件。它對內容處理本身的變化沒有影響。

TMemo.LinesTMemoStrings實現,它將文本內容存儲在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; 

注:一些評論提到複製含量和備忘錄時使用Assign代替Text屬性:Assign在這種情況下顯著慢,由於Text財產爲TMemoLines的內部優化。該屬性的Getter和Setter直接使用單個WM_GETTEXT/WM_SETTEXT消息訪問Windows控件,而Assign每行使用一個EM_GETLINE消息進行讀取,每行使用EM_LINEINDEX,EM_SETSEL,EM_LINELENGTH和EM_REPLACESEL序列進行寫入。簡單的時間測試表明上述代碼需要大約600毫秒,而用Assign代替Text分配需要超過11秒!

+5

使用'Assign()'方法代替'Text'屬性:'lst.Assign(Memo1.Lines); ... Memo1.Lines.Assign(lst);'由於這些行已經分開,只是按原樣複製它們,不要連接它們只是爲了重新解析它們,這是浪費內存和處理 –

+0

@RemyLebeau ,單獨獲取和設置每行代碼實際上就是原始代碼所做的。 –

+9

我知道這一點。我指的是將備忘錄內容複製到StringList然後回來。你的回答說'Text'屬性是「最有效的」方法,但這甚至不是真的,特別是對於100000行。 'Text' getter執行2遍掃描來分配和複製內存,然後'Text' setter解析輸入以執行大量的分配。另一方面,'Assign()'執行少得多的分配並使用1遍掃描。自己分析它,'Assign()'比'Text'更有效 –