2009-04-15 22 views
6

Tenemos una GUI de varios marcos que crean sus contenidos dinámicamente. Cada cuadro crea paneles, etiquetas, ediciones, cuadros combinados, etc., para usar como campos de entrada. Esto está funcionando muy bien y también estamos planeando dejar que cada marco genere su contenido en hilos separados.Delphi Win32: aceleración de controles creados dinámicamente (propiedad primaria)

Sin embargo, hay un gran problema: ¡es bastante lento! Crear los controles no lleva tiempo, pero establecer la propiedad Parent parece consumir mucho tiempo.

He intentado varias formas de acelerar el proceso pero sin suerte. He intentado con Enabled = False, Visible = False, DisableAlign, LockWindowUpdate, WM_SETREDRAW ... pero nada parece afectar el proceso lento de configuración de Parent de los controles.

Incluso si usamos hilos esto llevará tiempo ya que las funciones de VCL se deben llamar dentro de Sincronizar.

¿Hay alguna otra forma de acelerar la creación y la presentación de controles?

Saludos cordiales, Magnus

Editar: No hay datos componentes conscientes o eventos desencadenados en la GUI. Solo estoy creando los controles y mostrándolos. Utilizando cronómetros identifiqué la asignación de los controles padre (AControl.Parent: = AOwner) como la parte que consume mucho tiempo.

Editar 2: Como se muestra en la respuesta a continuación, el problema de velocidad no es configurar el elemento primario sino la pintura del control. Cuando probé el momento en que el contenedor era visible y la configuración del padre causó la pintura inmediata del control.

Editar 3: Otra parte que consume mucho tiempo de nuestra GUI dinámica es la asignación de elementos a cuadros combinados. ComboBox.Items.Assign (DataItems) donde DataItems no tiene más de tres o seis elementos.

¡Gracias a todos por tomarse el tiempo para ayudarme!

Respuesta

5

No intente utilizar varios hilos para crear controles o para trabajar con el VCL en general. Esto no va a mejorar la velocidad de todos modos, pero lo más importante es un completo no-no con el VCL.

Editar: Debe leer las otras preguntas y respuestas aquí en StackOverflow que tienen que ver con los hilos VCL y múltiples, pero en resumen: La VCL no es seguro para subprocesos, todo el acceso a los controles que hay que hacer en el contexto del hilo principal. Por lo tanto, al usar múltiples hilos, tendría que envolver casi todo en Sincronizar() llamadas, lo que realmente serializaría todos los hilos y ralentizaría aún más las cosas.

Su mejor opción es reestructurar su interfaz de usuario para que no sea necesario crearla de una sola vez. Cree todos los marcos a pedido, solo cuando se mostrarán por primera vez.

Edición 2: Aquí hay un código de prueba para demostrar que el establecimiento de la propiedad Parent no es el verdadero problema, pero la creación de todos los controles (con todo el manejo de mensaje que conlleva) probablemente lo es.

procedure TForm1.Button1Click(Sender: TObject); 
var 
    i, j, x, y: integer; 
    Edit: TEdit; 
    Ticks: LongWord; 
begin 
    Visible := FALSE; 
    DestroyHandle; 

    try 
    for i := 1 to 20 do begin 
     y := 20 + i * 25; 
     for j := 1 to 10 do begin 
     x := (j - 1) * 100; 

     Edit := TEdit.Create(Self); 
     Edit.SetBounds(x, y, 98, 23); 
     Edit.Parent := Self; 
     end; 
    end; 
    finally 
    Ticks := timeGetTime; 
    Visible := TRUE; 
    Caption := IntToStr(timeGetTime - Ticks); 
    end; 
end; 

el código crea dinámicamente 200 TEDIT controles, después de liberar el mango de la forma del padre. Crear todos esos controles y establecer sus propiedades toma unos 10 milisegundos en mi sistema, pero finalmente mostrar el formulario (que creará todas las ventanas) toma unos 100 milisegundos. Como esto solo se puede hacer en el hilo principal, dudo que usar varios hilos te ayude.

+0

El objetivo de varios hilos sería permitir que el usuario continúe trabajando en una parte de la interfaz de usuario mientras el contenido se carga en otras partes (marcos). Entiendo que puede que no sea más rápido, pero al menos el usuario no tendría que esperar a que termine. –

+0

Gracias, dejaré el hilo por el momento, aunque todavía me parece una buena idea. :-) –

2

No sé si esto funcionaría, pero ha intentado crear sus formularios como un formato de texto .dfm y luego usar la función ObjectTextToBinary cargar el .dfm directamente en la forma. Esto puede funcionar o no, vale la pena investigarlo.

+0

Es un pensamiento interesante, pero parece que hay un largo camino por recorrer para una tarea tan simple. La creación no es el problema sino la pintura/alineación de los controles y supongo que esto funcionaría de la misma manera si el marco se crea a partir de un flujo binario o no. Pero podría intentarlo. –

+0

@Magnus: Debería probarlo, a juzgar por el procedimiento de implementación TWinControl.InsertControl() muchas cosas simplemente se saltan cuando csReading está activo. Esta podría ser su mejor forma de avanzar. – mghie

1

Puede descargar la recuperación real de los datos al hilo de fondo, pero las cosas de la interfaz de usuario deben ocurrir en un hilo, el hilo principal. Entonces la configuración real de su marco sucederá en el mismo hilo.

¿Has probado un Profiler? Podría ser que su GUI esté demasiado conectada, y una actualización/cableado causa muchos eventos/efectos secundarios innecesarios. Usando un generador de perfiles puede obtener más información sobre lo que realmente causa el bajo rendimiento. Podría, por ejemplo, indicar que pasó mucho tiempo esperando que el DB regrese o podría ser que cada conjunto desencadena un evento que desencadena otro evento.

1

Si utiliza controles de dataware, asegúrese de llamar a DisableControls en TDataSet. Eso también puede causar muchos repintados.

0

Solo una conjetura descabellada: Tal vez ayude a establecer los padres de los controles en orden jerárquico inverso, es decir, primero establezca el padre de los controles más profundamente anidados, luego el de sus padres y demás. Que podría cortar algunas actualizaciones superfluas porque Windows aún no "sabe" sobre sus controles.

+0

Gracias, lo intenté pero el mismo resultado. –

2

¿Qué está configurando DisableAlign? Intente hacer una DisableAlign en cada control que pueda contener controles secundarios (por ejemplo, paneles). He visto DisableAlign como resultado una aceleración enorme para formas construidas dinámicamente antes.

Edit: Pensando en esto un poco más, mi respuesta fue parcialmente especulativa. No sé si el efecto de configurar DisableAlign en la raíz de un árbol de controles fluirá a sus hijos o no. Supuse que no, pero quizás sí. Tendría que mirar el código VCL. (Sin embargo, la parte sobre la aceleración era cierta.)

+0

Gracias, solo estaba desactivando el marco en sí. –

1

Otra conjetura: intente crear su contenedor (formulario, panel o marco) con Visible: = falso. A continuación, conecte todos los controles creados dinámicamente y establezca Visible: = verdadero

+0

Gracias He intentado esto. –

2

Encontré este problema hace algún tiempo y mejoré significativamente el tiempo de creación simplemente alojando los controles dentro de un marco 'temporal' (es decir, uno que no está asignado a una forma). Creo que la lentitud se debe a que cada control se comunica con el formulario principal (finalmente) para muchas llamadas, como SetBounds, SetVisible, etc. Al usar un marco flotante puede terminar con esto y luego asignar el marco a la forma que requieres

Cuestiones relacionadas