Listview sfarfalla sulla finestra Win32 durante la rimozione e ri-aggiungendo tutti gli elementi e tutte le colonne

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

Domanda

Si consideri una finestra Win32 pianura con controllo ListView (in modalità report) scritto in C ++. Su un determinato evento tutti gli elementi e tutte le colonne vengono cancellati e si creano nuove colonne e gli elementi. Fondamentalmente, il variare dei contenuti, le colonne vengono generati automaticamente in base al contenuto.

Quando i vecchi articoli / colonne vengono rimosse e quelli nuovi aggiunti, ListView tremola come l'inferno. Ho provato WM_SETREDRAW e LockWindowUpdate() con nessun cambiamento di esperienza visiva.

Ho anche impostare esteso stile listview LVS_EX_DOUBLEBUFFER e questo non ha aiutato affatto.

La finestra genitore ha impostato WS_CLIPCHILDREN.

Qualche suggerimento come fare questo lavoro con il minimo sfarfallio possibile? Sto pensando di utilizzare due listviews, visibilità alternata, utilizzando l'uno nascosto come un buffer di nuovo, ma questo suona come un peso inutile. Ci deve essere un modo semplice.

È stato utile?

Soluzione

Il quadro di controllo elenco predefinito è abbastanza difettosa. Ma v'è un semplice trucco per implementare la propria tecnica doppio buffering:

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

Questo creerà una bitmap e poi chiamare la procedura di finestra predefinita di dipingere il controllo elenco in bitmap e poi copiarlo sul video il contenuto della bitmap nella vernice DC.

Si dovrebbe anche aggiungere un gestore per WM_ERASEBKGND:

BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}

Questo fermerà il controllo dal cancellando sempre sullo sfondo prima di un ridisegno. È possibile ottimizzare l'OnPaint ulteriormente se si aggiunge una variabile membro per la bitmap e solo (ri) creare quando la dimensione della finestra cambia (perché la creazione di sempre di una bitmap può essere costoso a seconda della dimensione della finestra).

Questo dovrebbe funzionare abbastanza bene.

Altri suggerimenti

Dopo aver provato molte cose e la maggior parte di tutti i suggerimenti di humbagumba sono venuto a una conclusione molto semplice. LockWindowUpdate è amico di tutti in questo tipo di situazione. Non so come mai non ha funzionato per me la prima volta, ma dopo personalizzato pittura riuscito a consegnare in tutte le situazioni che ho provato LockWindowUpdate ancora una volta e ha funzionato!

In sostanza, basta avvolgere tutto il lavoro su ListView in un LockWindowUpdate(hWnd) e LockWindowUpdate(NULL) e le cose funzionano in modo bello. Non c'è nemmeno un guizzo barra di scorrimento più.

Proprio sicuri di non fare a nido LockWindowUpdate come solo una finestra può essere bloccato alla volta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top