ListView Flickers на диалоговом окне Win32 при удалении и восстановлении всех элементов и всех столбцов

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

Вопрос

Рассмотрим простое диалоговое окно Win32 со элементом управления ListView (в режиме отчета), написанным в C ++. После определенного события все элементы и все столбцы удаляются, и создаются новые столбцы и элементы. По сути, поскольку изменения контента столбцы автоматически генерируются на основе контента.

Когда старые предметы / столбцы удалены, а новые добавлены, ListView пропускает как ад. я пытался WM_SETREDRAW а также LockWindowUpdate() без изменения визуального опыта.

Я даже установил расширенный стиль ListView LVS_EX_DOUBLEBUFFER И это вообще не помогло.

Родительский диалог имеет WS_CLIPCHILDREN задавать.

Любые предложения Как сделать эту работу как можно меньше мерцания? Я думаю об использовании двух ListViews, чередуя видимость, используя скрытый в качестве заднего буфера, но это звучит как излишки. Там должен быть простой способ.

Это было полезно?

Решение

Картина управления списком по умолчанию довольно ошибка. Но есть простой трюк для реализации вашей собственной методики двойного буферизации:

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

Это остановит контроль от всегда стирания фона перед RedRaw. Далее вы можете оптимизировать OnPaint, если добавить переменную элемента для растрового изображения и только (Re) создавать его, когда размер окна изменен (потому что всегда создавая растровое изображение может быть дорогостоящим в зависимости от размера окна).

Это должно работать довольно хорошо.

Другие советы

После пробования многое и больше всего humbagumbaПредложения я пришли к очень простому выводу. LockWindowUpdate Это друг каждого в такой ситуации. Я не уверен, как придет, не смогли работать для меня в первый раз, но после того, как пользовательская картина не смогла доставить во всех ситуациях, которые я пробовал LockWindowUpdate Еще раз и это сработало!

В основном, просто оберните все работы на ListView в LockWindowUpdate(hWnd) а также LockWindowUpdate(NULL) И все работает красиво. Даже больше не мерцает прокрутки.

Просто убедитесь, что не гнездить LockWindowUpdate Как только одно окно может быть заблокировано за раз.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top