Listview scintille sur dialogue Win32 lors de la suppression et re ajoutée tous les éléments et toutes les colonnes
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.
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.