Listview flickers on Win32 dialog when removing and re-adding all items and all columns
Consider a plain Win32 dialog with listview control (in report mode) written in C++. Upon a certain event all items and all columns are deleted and new columns and items are created. Basically, as content changes开发者_JS百科, columns are automatically generated based on content.
When old items/columns are removed and new ones added, listview flickers like hell. I have tried WM_SETREDRAW
and LockWindowUpdate()
with no change to visual experience.
I have even set extended listview style LVS_EX_DOUBLEBUFFER
and that didn't help at all.
The parent dialog has WS_CLIPCHILDREN
set.
Any suggestions how to make this work with as little flicker as possible? I am thinking of using two listviews, alternating visibility, using the hidden one as a back buffer but this sounds like an overkill. There must be an easy way.
The default list control painting is pretty flawed. But there is a simple trick to implement your own double-buffering technique:
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);
}
}
This will create a bitmap and then call the default window procedure to paint the list control into the bitmap and then blitting the contents of the bitmap into the paint DC.
You should also add a handler for WM_ERASEBKGND:
BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
This will stop the control from always erasing the background before a redraw. You can optimize the OnPaint further if you add a member variable for the bitmap and only (re)create it when the size of the window changed (because always creating a bitmap may be costly depending on the size of the window).
This should work pretty well.
After trying many things and most of all humbagumba
's suggestions I have come to a very simple conclusion. LockWindowUpdate
is everybody's friend in this sort of situation. I am not sure how come it failed to work for me the first time but after custom painting failed to deliver in all situations I have tried LockWindowUpdate
once again and it worked!
Basically, just wrap all work on listview in a LockWindowUpdate(hWnd)
and LockWindowUpdate(NULL)
and things work beautifully. There is not even a scrollbar flicker any more.
Just make sure not to nest LockWindowUpdate
as only one window can be locked at a time.
精彩评论