2012-02-05 25 views
13

Tôi hiểu rằng việc sử dụng BeginUpdate và EndUpdate trên các điều khiển VCL chẳng hạn như TListBox tăng tốc quá trình điều khiển với các mục vì nó ngăn không cho kiểm soát được sơn lại, cho đến khi EndUpdate được gọi.Tại sao TStringList có BeginUpdate và EndUpdate?

Ví dụ:

procedure TForm1.AddItems; 
var 
    i: Integer; 
begin 
    Screen.Cursor := crHourGlass; 
    try 
    for i := 0 to 5000 do 
    begin 
     ListBox1.Items.Add('Item' + IntToStr(i)); 
    end; 
    finally 
    Screen.Cursor := crDefault; 
    end; 
end; 

trên sẽ có một sự chậm trễ vì Listbox được phép được sơn lại, nhưng sự chậm trễ có thể thiếu bằng cách ngăn chặn sơn lại như vậy:

procedure TForm1.AddItems; 
var 
    i: Integer; 
begin 
    Screen.Cursor := crHourGlass; 
    try 
    ListBox1.Items.BeginUpdate; 
    try 
     for i := 0 to 5000 do 
     begin 
     ListBox1.Items.Add('Item' + IntToStr(i)); 
     end; 
    finally 
     ListBox1.Items.EndUpdate; 
    end; 
    finally 
    Screen.Cursor := crDefault; 
    end; 
end; 

Bây giờ tôi đã thử nghiệm điều này bằng cách sử dụng TStringList:

procedure TForm1.AddItems; 
var 
    SL: TStringList; 
    i: Integer; 
begin 
    SL := TStringList.Create; 
    try 
    Screen.Cursor := crHourGlass; 
    try 
     SL.BeginUpdate; 
     try 
     for i := 0 to 5000 do 
     begin 
      SL.Add('Item' + IntToStr(i)); 
     end; 
     finally 
     SL.EndUpdate; 
     end; 

     ListBox1.Items.Assign(SL); 
    finally 
     Screen.Cursor := crDefault; 
    end; 
    finally 
    SL.Free; 
    end; 
end; 

Dường như không phân biệt nếu TStringList sử dụng BegindUpdate và EndUpdate, danh sách này được phổ biến ở mức xấp xỉ với tốc độ tương tự ..

Họ có thực sự cần thiết mặc dù là TStringList được thực hiện trong bộ nhớ và không trực quan. Tôi có nên sử dụng BeginUpdate và EndUpdate trên TStringList hay không, liệu có thực hành tốt để làm điều này không?

Tôi cảm thấy ngớ ngẩn khi hỏi điều này nhưng tại sao TStringList lại có các thủ tục BeginUpdate và EndUpdate?

Tôi nghĩ rằng tôi có thể đã trả lời câu hỏi của riêng tôi ở đây, theo cách tôi muốn nghe quan điểm của bạn.

Cảm ơn :)

Trả lời

21

Các BeginUpdate ức chế sự OnChangingOnChange sự kiện của stringlist. Tùy thuộc vào những gì được kết nối, nó có thể tăng tốc độ đáng kể.

Trong ví dụ của bạn, BeginUpdate/EndUpdate không tạo ra nhiều khác biệt. Sử dụng một cá thể TStringlist và gán nó vào listview là một cách tiếp cận khá hợp lệ.

+0

+1, Cũng ức chế sự kiện 'OnChange'. – RRUZ

+0

@RRUZ, thực sự! Cảm ơn gợi ý. –

+0

Cảm ơn tuyệt vời @UweRaabe Tôi sẽ không biết rằng –

10

BeginUpdateEndUpdate được giới thiệu trong lớp cơ sở trừu tượng TStrings. Vì vậy, TStringList thừa hưởng khả năng này mặc dù nó không đặc biệt hữu ích. Tuy nhiên, nó tất nhiên hữu ích cho nhiều người khác TStrings hậu duệ.

Hãy nhớ rằng nhiều người khác TStrings hậu duệ có triển khai riêng tư. Ví dụ: đối tượng TStrings được liên kết với một TListBox là riêng tư cho phần triển khai của đơn vị StdCtrls. Điều khiển TListBox hiển thị danh sách mục là TStrings và do đó, để làm cho BeginUpdateEndUpdate có sẵn, chúng cần phải được khai báo trong lớp cơ sở trừu tượng.

Theo quan điểm của tôi, bạn có thể bỏ qua các phương pháp này một cách an toàn khi làm việc với đối tượng mà bạn biết là TStringList.

Bây giờ, liên quan đến mã điền vào chế độ xem danh sách, tôi không thấy bất kỳ điểm nào khi sử dụng số trung gian TStringList. Tôi chỉ đơn giản sẽ điền trực tiếp chế độ xem danh sách và sử dụng BeginUpdate/EndUpdate trên chế độ xem danh sách Items. Nếu bạn vẫn gặp vấn đề về hiệu suất với chế độ xem danh sách thì giải pháp là chế độ xem danh sách ảo.

+1

+1, Việc sử dụng trực tiếp của TListBox.Items.Add thực sự có thể nhanh hơn một chút, như TListBox.Items.Assign cuộc gọi TStrings.AddObject cho mỗi mục, trong đó gọi nội bộ Thêm và PutObject. –

+0

@Uwe Điều đó sẽ hoàn toàn không đáng kể so với việc gửi dữ liệu đến điều khiển chung. Đó sẽ là nút cổ chai. Một khi bạn đã thực hiện BeginUpdate trên các mục của danh sách xem thì tất cả các biến thể sẽ mất cùng một lúc. –

+1

Nhưng TListBoxStrings.PutObject gọi ListBox.SetItemData cũng được thực hiện với một SendMessage. Vì vậy, nó là một SendMessage cho mỗi mục so với hai SendMessages cho mỗi mục. –

2

Chỉ là triển khai mẫu mã khóa như được giải thích here.

Nó cho phép bạn temporarily lock một khía cạnh của lớp học, tránh thông báo không cần thiết.

Khá giống như bạn có thể tìm thấy trong DB.TDataSet.DisableControlsDB.TDataSet.EnableControls.

Các vấn đề liên quan