Listview scintille sur dialogue Win32 lors de la suppression et re ajoutée tous les éléments et toutes les colonnes

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

Question

Considérons une boîte de dialogue Win32 simple avec contrôle listview (en mode rapport) écrit en C ++. Lors d'un événement tous les éléments et toutes les colonnes sont supprimés et de nouvelles colonnes et les éléments sont créés. Fondamentalement, comme les changements de contenu, les colonnes sont générées automatiquement en fonction du contenu.

Lorsque les anciens éléments / colonnes sont supprimés et de nouveaux ajoutés, listview scintille comme l'enfer. J'ai essayé WM_SETREDRAW et LockWindowUpdate() sans changement à l'expérience visuelle.

Je l'ai même mis en LVS_EX_DOUBLEBUFFER style ListView étendu et cela n'a pas aidé du tout.

La boîte de dialogue parent a WS_CLIPCHILDREN ensemble.

Toutes les suggestions comment faire ce travail avec aussi peu de scintillement possible? Je pense à l'aide de deux listviews, la visibilité en alternance, à l'aide d'une cache comme un tampon de retour, mais cela sonne comme un surpuissant. Il doit y avoir un moyen facile.

Était-ce utile?

La solution

Le tableau de contrôle de la liste par défaut est assez erronée. Mais il y a une astuce simple à mettre en œuvre votre propre technique à double mémoire tampon:

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);
    }
}

Cela va créer une image bitmap, puis appelez la procédure de fenêtre par défaut pour peindre le contrôle de liste dans le bitmap et blitting alors le contenu du bitmap dans la peinture DC.

Vous devez également ajouter un gestionnaire pour WM_ERASEBKGND:

BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}

Cela arrêtera le contrôle d'effacer toujours l'arrière-plan avant un nouveau tracé. Vous pouvez optimiser le OnPaint plus si vous ajoutez une variable membre pour le bitmap et seulement (re) créer lorsque la taille de la fenêtre a changé (parce que la création toujours une image bitmap peut être coûteux en fonction de la taille de la fenêtre).

Cela devrait fonctionner assez bien.

Autres conseils

Après avoir essayé beaucoup de choses et la plupart des suggestions de tous humbagumba Je suis venu à une conclusion très simple. LockWindowUpdate est l'ami de tout le monde dans ce genre de situation. Je ne sais pas comment se fait-il pas fonctionné pour moi la première fois, mais après la peinture sur mesure de livrer dans échouais toutes les situations que j'ai essayé LockWindowUpdate encore une fois et cela a fonctionné!

En fait, tout simplement envelopper tous les travaux sur listview dans un LockWindowUpdate(hWnd) et LockWindowUpdate(NULL) et les choses fonctionnent à merveille. Il n'y a même pas une lueur scrollbar plus.

Assurez-vous de ne pas nicher LockWindowUpdate comme une seule fenêtre peut être bloquée à la fois.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top