Listview parpadea en el cuadro de diálogo Win32 al quitar y volver a agregar todos los elementos y todas las columnas

StackOverflow https://stackoverflow.com/questions/3150108

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.

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top