Listview мерцает в диалоговом окне Win32 при удалении и повторном добавлении всех элементов и всех столбцов
Рассмотрим простой диалог Win32 с контролем списка (в режиме отчета), написанный на C++. После определенного события все элементы и все столбцы удаляются, и создаются новые столбцы и элементы. Как правило, при изменении содержимого столбцы автоматически создаются на основе содержимого.
Когда старые элементы / столбцы удаляются и добавляются новые, просмотр списка мерцает как ад. я пытался WM_SETREDRAW
а также LockWindowUpdate()
без изменений в визуальном опыте.
Я даже установил расширенный стиль списка LVS_EX_DOUBLEBUFFER
и это совсем не помогло.
Родительский диалог имеет WS_CLIPCHILDREN
задавать.
Любые предложения, как сделать это работать с минимальным мерцанием, насколько это возможно? Я подумываю использовать два списка, чередуя видимость, используя скрытый в качестве заднего буфера, но это звучит как излишнее. Там должен быть легкий путь.
2 ответа
Рисование элемента управления списком по умолчанию довольно некорректно. Но есть простой прием для реализации собственной техники двойной буферизации:
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);
}
}
Это создаст растровое изображение, а затем вызовет оконную процедуру по умолчанию, чтобы нарисовать элемент управления списком в растровое изображение, а затем скопировать содержимое растрового изображения в DC рисования.
Вы также должны добавить обработчик для WM_ERASEBKGND:
BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
Это остановит элемент управления от всегда стирания фона перед перерисовкой. Вы можете оптимизировать OnPaint дальше, если добавите переменную-член для растрового изображения и только (заново) создадите ее, когда размер окна изменился (потому что всегда создание растрового изображения может быть дорогостоящим в зависимости от размера окна).
Это должно работать очень хорошо.
Попробовав много вещей и больше всего humbagumba
Из предложений я пришел к очень простому выводу. LockWindowUpdate
друг каждого в такой ситуации. Я не уверен, почему у меня это не получилось в первый раз, но после нестандартной покраски не получилось во всех ситуациях, которые я пытался LockWindowUpdate
еще раз и это сработало!
В основном, просто оберните всю работу над списком в LockWindowUpdate(hWnd)
а также LockWindowUpdate(NULL)
и все работает прекрасно. Больше нет мерцания полосы прокрутки.
Просто убедитесь, что не гнездятся LockWindowUpdate
поскольку только одно окно может быть заблокировано за один раз.