0
votes

I've a problem with my code. I've created a class for Drag & Drop but during the dragging of the object i see a annoying flickering effect for the object that i'm dragging

void CDragDropListBox::DrawDragRect(CPoint point, CDragItem* DragItem,SIZE Size)
{
    CDC* pDC = GetDC();
    ScreenToClient(&point);

    //Rect centered under mouse pointer
    point.x -= Size.cx/2;
    point.y -= Size.cy/2;

    CRect rectFull(point,m_RectSize);

    //Delete previous rect
    ClientToScreen(&m_OldRect);
    _DstWnd->ScreenToClient(&m_OldRect);
    _DstWnd->InvalidateRect(m_OldRect, true);
    _DstWnd->UpdateWindow();

    //Draw new rect based on mouse position
    DrawSelectFrame(pDC,rectFull);
    DrawSingleItem(DragItem,pDC,rectFull);

    m_OldRect = rectFull;
}

In my code every time i move the mouse i delete the previously drawn drag-rect and paint a new one, but the flickering is very fastidious... There is anything i can do?

2
Sure, your UpdateWindow() call forces the window to repaint without a rectangle visible. Then you paint the rectangle again. Flickers like a cheap motel. Making the WM_PAINT handler aware of having to draw the rectangle is the workaround. Use InvalidateRect() with the union of the old and new rectangles to ask for an update. - Hans Passant
I'm sorry but I did not understand. InvalidateRect takes a single rect parameter, I don't understand how i can use it to upgrade both the rect. - Eddie

2 Answers

0
votes

The main problem here is, that the erasing and painting is done in two steps. And even if it is executed fast. It looks like flickering.

So don't use WM_ERASEBKGND, and use double buffering (with a memory DC) in WM_PAINT.

See CMemDC in Codeproject for a good and easy class.

0
votes

I've edited my code for remove the use of UpdateWindow()

   void CDragDropListBox::DrawDragRect(CPoint point, CDragItem* DragItem,SIZE Size)
{
    CDC* pDC = _DstWnd->GetDC();
    CDC dcMemory;

    ScreenToClient(&point);
    dcMemory.CreateCompatibleDC(pDC);

    CDC* olddc= pDC;

    CRect tmprect;
    pDC->GetClipBox(&tmprect);

    CBitmap tmpbmp;
    tmpbmp.CreateCompatibleBitmap(pDC, tmprect.Width(), tmprect.Height());

    CBitmap* OldBmp;
    OldBmp = dcMemory.SelectObject(&tmpbmp);

    point.x -= Size.cx/2;
    point.y -= Size.cy/2;

    CRect rectFull(point,m_RectSize);

    ClientToScreen(&m_OldRect);
    _DstWnd->ScreenToClient(&m_OldRect);
    _DstWnd->InvalidateRect(m_OldRect, TRUE);

    m_OldRect = rectFull;

    ClientToScreen(&rectFull);
    _DstWnd->ScreenToClient(&rectFull);
    DrawSelectFrame(pDC,rectFull);
    DrawSingleItem(DragItem,pDC,rectFull);
    _DstWnd->ValidateRect(rectFull);

    //_DstWnd->UpdateWindow();

    olddc->BitBlt(tmprect.left, tmprect.top, tmprect.Width(), tmprect.Height(), pDC, tmprect.left, tmprect.top, SRCCOPY);

    dcMemory.SelectObject(OldBmp);

}

Flickering less, but can i further improve?