2010-10-11 16 views
5

Bien, entonces en mi aplicación, hay un montón de winAPI y algunos controles personalizados. Yay ...Doble buffering winAPI

Ahora, normalmente, se redibujarán silenciosamente para las animaciones, los cambios de estado, etc. ... y todo funciona bien.

Pero tengo un método de clase Window llamado fix(). Esto se llama cuando la ventana completa necesita ser actualizada. Cambia el tamaño de los controles e invalida la ventana.

Cuando esto sucede, se dibuja el fondo, luego el control de pestañas y luego todos los demás en la parte superior. Esto provoca un parpadeo muy irritante, especialmente al cambiar el tamaño de la ventana (debido a las constantes llamadas a la corrección()).

Lo que he intentado:

  • WS_EX_COMPOSITED. Esto solo duplica los amortiguadores individuales. Es una mejora, pero el parpadeo inevitablemente permanece.
  • Desactivación del dibujo de fondo. Difícilmente resuelve el problema, y ​​en realidad empeora las cosas.

Así que: Necesito una técnica/método/lo que sea que me permita duplicar la ventana en su totalidad. Pensé que manejar el mensaje WM_PAINT podría ser una solución, pero no sabría por dónde empezar. Tengo la horrible sensación de que esto ni siquiera es posible ...

Por favor, ayuda, este es un problema crítico. Me sentiré muy aliviado cuando se solucione este pequeño problema estúpido.

+0

¿Tal vez esta página? http://www.gamedev.net/community/forums/topic.asp?topic_id=411559 –

Respuesta

4

Es en este momento que uno se dio cuenta de las profundidades de desprecio de Microsofts por los desarrolladores nativos. De hecho, uno podría comenzar a albergar paranoias ilusiones de que Microsoft ha roto deliberadamente la pintura nativa para obligar a los desarrolladores nativos a mudarse a WPF.

Primero, considere WS_EX_COMPOSITED. WS_EX_COMPOSITED parece ser la mostaza: dice que impone un botton al orden superior de pintura para controles secundarios, y básicamente que los mensajes WM_PAINT se manejan en un lote. Dice que fue agregado en Windows 2000 (5.0) y, algunas líneas abajo, que no funciona con la composición de escritorio habilitada. es decir, deja de funcionar a partir de Windows Vista (6.0), a menos que el aero vidrio esté apagado y ¿quién lo hará?

Entonces, hay dos posibles "hacks" para tratar de conseguir el parpadeo pintura libre de trabajar:

  • En primer lugar, usted necesita mimimize la cantidad de repintes. WS_EX_CLIPCHILDREN | WS_EX_CLIPSIBLINGS son necesarios para garantizar que cualquier área particular de la ventana solo se pinta una vez. BeginDeferWindowPos también es necesario para procesar las operaciones de cambio de tamaño para garantizar que los estados transitorios, donde una ventana se superpone a otra, no sucedan (es decir, cuando se ha redimensionado la ventana A, pero la ventana B no lo ha hecho).

Por supuesto, cuando usted está tratando de dibujar un cuadro de diálogo de piel, o el uso de marcos de grupo, o controles de ficha, o cualquier número de otras restricciones, WS_EX_CLIPSIBLINGS no es sólo apropiado.

  • WM_SETREDRAW es un mensaje mágico. No hay API para acceder a esta funcionalidad: WM_SETREDRAW es manejado directamente por DefWindowProc para marcar esencialmente la ventana como oculta para la duración. Después de que se envíe WM_SETREDRAW, FALSE, las llamadas a GetDC/GetDCEx/GetWindowDC etc. utilizando el manejador de la ventana principal (y todos sus elementos secundarios) devolverán un DC que no dibujará en la pantalla. Esto le da la oportunidad de hacer todo tipo de cosas en las ventanas secundarias, cuando haya terminado, envíe un WM_SETREDRAW,TRUE (y vuelva a pintar la ventana manualmente). Todas las ventanas hijas, por supuesto, pintarán en su momento, y después de que la ventana principal haya borrado el fondo, WM_SETREDRAW no es una panacea.

Después de romper WS_EX_COMPOSITED, En WinForms de .NET y WPF re-escribió los controles desde el suelo hasta que no utilice los controles nativos, para que pudieran cocer en la pintura tamponada allí. Y soporte alfa también.

0

Sin código, no me imagino cuál es la situación real ... Pero puede tratar de manejar WM_ERASEBKGND, devolver TRUE cuando los reciba para omitir el borrado.

+0

Intenté esto. Simplemente hizo un gran desastre. ¿Sabes lo que sucede cuando no borras el fondo? –

+0

fondo no está "borrado" obviamente:>. Bueno, si su pintura cubre toda el área, no importa si se borra o no. – YeenFei

1

Hm. Antes de que la gente se apresure y cierre este tema como un duplicado, mejor menciono que su problema no es el doble buffer per se, sino que parpadea cuando reposiciona los controles, para lo cual el doble buffer "manual" es solo una de varias soluciones.

Puede ser que, p. BeginDeferWindowPos & amigos pueden corregir el parpadeo.

Descargo de responsabilidad: Una vez conocí casi todos los detalles de la API de Win16, pero han pasado algunos años desde que hice la programación de nivel API.

Saludos & HTH,

-. Alf

+0

esto es win32 ... –

+0

@Alexander, win32 es solo win16s menos gemelo malvado. –

0

Handle WM_ERASEBKGND para su ventana y en la puesta en práctica excluyen las rectas de cada uno de sus niños controles, a continuación, rellenar el fondo restante de manera adecuada y decirle al marco que se ha pintado el fondo urself devolviendo true. Haga lo mismo para todos los demás controles secundarios que a su vez contienen otros controles como control de pestañas en su caso.

Vea un ejemplo en el here usando MFC.

+0

Esta es una solución no deseada. Tal vez como último recurso ... –

1

En .net hay ControlStyle.AllPaintingInWmPaint que se debe establecer en cada ventana del contenedor (por lo que la ventana principal y las pestañas). No pude encontrar un equivalente winapi. Pero lo que hace es mover la pintura del fondo de WM_ERASEBKGND a WM_PAINT. también resta el área del control secundario del elemento principal para evitar el parpadeo. Puede ser que deba hacer esto manualmente.

Me sorprende WS_EX_COMPOSITED no ayuda. Eso debería funcionar, si configura eso en la ventana de nivel superior, y no llama a RedrawWindow en los subcontroles.

También asegúrese de probar con y sin DWM/Aero. Puedes obtener diferentes resultados.

+0

P.S. Puse un ejemplo de código C de muestra en una respuesta anterior mía. Puede modificarlo para demostrar el efecto que está viendo. http: // stackoverflow.com/questions/3735121/direct2d-gdi-and-slow-windows-forms-drawing-what-can-be-done/3735328 # 3735328 –

+0

Podría borrar manualmente el fondo en WM_PAINT. –

+0

@Alexander: eso es lo que debes hacer. También debe volver verdadero en WM_ERASEBKGND. También puede ser necesario excluir los recuentos de la ventana secundaria de la pintura (tal vez agregar WS_CLIPCHILDREN hará el truco). –