Listview parpadea en el cuadro de diálogo Win32 al quitar y volver a agregar todos los elementos y todas las columnas
Pregunta
Considere un diálogo Win32 llano con el control listview (en el modo de informe) escrito en C ++. Tras un determinado evento todos los elementos y todas las columnas se eliminan y nuevas columnas y artículos son creados. Básicamente, como cambios en el contenido, las columnas se generan de forma automática basándose en el contenido.
Cuando los elementos antiguos / columnas se retiran y se añaden otros nuevos, listview parpadea como el demonio. He tratado WM_SETREDRAW
y LockWindowUpdate()
sin ningún cambio en la experiencia visual.
He incluso fijar LVS_EX_DOUBLEBUFFER
estilo de vista de lista extendida y eso no ayuda en absoluto.
El diálogo de los padres tiene WS_CLIPCHILDREN
conjunto.
Alguna sugerencia de cómo hacer este trabajo con el menor parpadeo como sea posible? Estoy pensando en usar dos de listas, la visibilidad alterna, mediante el que se esconde como un amortiguador de vuelta, pero esto suena como una exageración. Tiene que haber una manera fácil.
Solución
El cuadro de control de lista por defecto es bastante defectuoso. Pero hay un truco sencillo para implementar su propia técnica de doble búfer:
CMyListCtrl::OnPaint()
{
CRect rcClient;
GetClientRect(rcClient);
CPaintDC dc(this);
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
CBitmap bmMem;
bmMem.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
CBitmap* pbmOld = dcMem.SelectObject(&bmMem);
dcMem.FillSolidRect(rcClient, ::GetSysColor(COLOR_WINDOW));
this->DefWindowProc(WM_PAINT, (WPARAM)dcMem.m_hDC, (LPARAM)0);
dc.BitBlt(0,0,rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);
dcMem.SelectObject(pbmOld);
CHeaderCtrl* pCtrl = this->GetHeaderCtrl();
if (::IsWindow(pCtrl->GetSafeHWnd())
{
CRect aHeaderRect;
pCtrl->GetClientRect(&aHeaderRect);
pCtrl->RedrawWindow(&aHeaderRect);
}
}
Esto creará un mapa de bits y luego llamar al procedimiento de ventana por defecto para dibujar el control de lista en el mapa de bits y luego blitting el contenido del mapa de bits en la pintura de CC.
También debe agregar un controlador para WM_ERASEBKGND:
BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
Esto detendrá el control desde siempre borrando el fondo ante un redibujado. Puede optimizar la OnPaint aún más si se agrega una variable miembro para el mapa de bits y sólo se (re) crear cuando el tamaño de la ventana cambia (porque siempre la creación de un mapa de bits puede ser costoso, dependiendo del tamaño de la ventana).
Esto debería funcionar bastante bien.
Otros consejos
Después de probar muchas cosas y la mayoría de las sugerencias de todos los humbagumba
he llegado a una conclusión muy simple. LockWindowUpdate
es amigo de todo el mundo en este tipo de situación. No estoy seguro de cómo es que se no funcionó para mí la primera vez, pero después de costumbre fallado pintura para entregar en todas las situaciones que he intentado LockWindowUpdate
una vez más y funcionó!
Básicamente, simplemente envolver todo el trabajo en vista de lista en un LockWindowUpdate(hWnd)
y LockWindowUpdate(NULL)
y las cosas funcionan muy bien. No hay ni siquiera un parpadeo barra de desplazamiento más.
Sólo asegúrese de no hacer a LockWindowUpdate
nido tan sólo una ventana se puede bloquear a la vez.