2012-02-05 17 views
13

Entiendo que el uso de BeginUpdate y EndUpdate en controles VCL como TListBox acelera el proceso de llenar el control con Elementos, ya que impide que el control se vuelva a pintar, hasta que se llame a EndUpdate.¿Por qué TStringList tiene BeginUpdate y EndUpdate?

Ejemplo:

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; 

Lo anterior tendrá un retraso porque se permite que el cuadro de lista para ser pintada, pero el retraso puede ser cortocircuitado mediante la prevención de repintado de este modo:

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; 

Ahora he probado esto usando una lista de líneas de TSTR:

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; 

Parece que no importa si el TStringList utiliza BegindUpdate y EndUpdate, la lista se llena aproximadamente a la misma velocidad ..

¿son realmente necesarios, ya que el TStringList se realiza en memoria y no visualmente. Si de todos modos utilizo BeginUpdate y EndUpdate en una TStringList, ¿es una buena práctica hacer esto?

Me siento tonto por preguntar esto, pero ¿por qué TStringList tiene los procedimientos BeginUpdate y EndUpdate?

Creo que puedo haber respondido mi propia pregunta aquí, de cualquier manera me gustaría escuchar sus opiniones.

Gracias :)

Respuesta

21

El BeginUpdate inhibe la OnChanging y OnChange acontecimientos de la StringList. Dependiendo de lo que esté conectado, puede acelerar las cosas significativamente.

En su ejemplo, el BeginUpdate/EndUpdate no hace mucha diferencia. Usar una instancia de TStringlist y asignarla a la vista de lista es un enfoque bastante válido.

+0

+1, también inhibe el evento 'OnChange'. – RRUZ

+0

@RRUZ, de hecho! Gracias por la pista. –

+0

Muchas gracias @UweRaabe No sabía que –

10

BeginUpdate y EndUpdate se presentan en la clase base abstracta TStrings. Por lo tanto, TStringList hereda esta capacidad aunque no sea particularmente útil. Sin embargo, es, por supuesto, útil para muchos otros descendientes TStrings.

Recuerde que muchos otros descendientes de TStrings tienen una implementación privada. Por ejemplo, el objeto TStrings asociado con un TListBox es privado para la sección de implementación de la unidad StdCtrls. El control TListBox expone la lista de elementos como TStrings y, por lo tanto, para hacer que BeginUpdate y EndUpdate estén disponibles, deben declararse en la clase base abstracta.

En mi opinión, puede ignorar estos métodos al trabajar con un objeto que sabe que es TStringList.

Ahora, con respecto al código que puebla la vista de lista, no veo ningún punto en el uso de un intermediario TStringList. Me gustaría simplemente llenar la vista de lista directamente y hacer uso de BeginUpdate/EndUpdate en la vista de lista Items. Si todavía tiene problemas de rendimiento con su vista de lista, entonces la solución es una vista de lista virtual.

+1

+1, el uso directo de TListBox.Items.Add podría ser un poco más rápido, ya que TListBox.Items.Assign llama a TStrings.AddObject para cada entrada, que internamente llama Add y PutObject. –

+0

@Uwe Eso va a ser completamente insignificante en comparación con enviar los datos al control común. Ese va a ser el cuello de botella. Una vez que haya realizado BeginUpdate en los elementos de la vista de lista, todas las variantes tomarán el mismo tiempo. –

+1

Pero TListBoxStrings.PutObject llama a ListBox.SetItemData que también se implementa con SendMessage. Por lo tanto, es un SendMessage por artículo en comparación con dos SendMessages por artículo. –

2

Es solo una implementación del patrón de bloqueo según se explica here.

Le permite a usted temporarily lock un aspecto de la clase, evitando notificaciones innecesarias.

exactamente lo mismo que usted puede encontrar en DB.TDataSet.DisableControls y DB.TDataSet.EnableControls.

Cuestiones relacionadas