Listview мерцает в диалоге Win32 при удалении и повторном добавлении всех элементов и всех столбцов - PullRequest
3 голосов
/ 30 июня 2010

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

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

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

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

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

Ответы [ 2 ]

7 голосов
/ 30 июня 2010

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

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, если добавите переменную-член для растрового изображения и только (заново) создадите ее, когда размер окна изменился (поскольку всегда создание растрового изображения может быть дорогостоящим в зависимости от размера окна).

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

1 голос
/ 30 июня 2010

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

По сути, просто оберните всю работу над списком в LockWindowUpdate(hWnd) и LockWindowUpdate(NULL), и все будет работать прекрасно. Больше нет даже мерцания полосы прокрутки.

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

...