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 поскольку только одно окно может быть заблокировано за один раз.

Другие вопросы по тегам