65.9K
CodeProject is changing. Read more.
Home

Overcome Window Flicker while Dragging with CImageList

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (6 votes)

Jun 5, 2009

CPOL

1 min read

viewsIcon

25607

downloadIcon

999

Overcome window flicker while dragging with CImageList

Introduction

While I use CImageList control for dragging, I found its owner window flickers while dragging and redraw the client region. I tried Google to find a solution, but did not find any results, so I tried to solve it by myself. Here is my solution and I am very glad to share it with you!

Background

First, register a new window class and create a new topmost, toolwindow, and move its position far off screen (I take 99000), so it's not visible. The code is like this:

BOOL CImageDragWrapper::Initialize() 
{ 
if(m_hDragWnd)
{
return TRUE;
}
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX); 

if(!::GetClassInfoEx(AfxGetInstanceHandle(), POPWINDOWCLASSNAM, &wcex))
{ 
wcex.style = CS_HREDRAW | CS_VREDRAW;
//specifies default window procedure 
wcex.lpfnWndProc = (WNDPROC)DefWindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = AfxGetInstanceHandle();
wcex.hIcon = LoadIcon(0, IDI_INFORMATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = POPWINDOWCLASSNAM;
wcex.hIconSm = LoadIcon(0, IDI_INFORMATION); 
RegisterClassEx(&wcex);
}

m_hDragWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
POPWINDOWCLASSNAM,
_T(""),
WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
99000, 0, 6, 6,
0,
0,
AfxGetInstanceHandle(),
0
);

if(m_hDragWnd)
{
SetLayeredWindowAttributes(RGB(255,255,255), 100, /*0x00000001|*/0x0000002);

ShowWindow(m_hDragWnd, SW_SHOW);
UpdateWindow(m_hDragWnd);
}

return m_hDragWnd != 0;
}

Second, move window to proper position and paint its client code like this:

BOOL CImageDragWrapper::DragBegin(HWND hDragWndOwner,int cxWnd, int cyWnd, 
int cxHotSpotOffset, int cyHotSpotOffset,
const POINT& ptCurrentMousePos, HBITMAP hBack, int cxBackOffset, int cyBackOffset)
{
if(m_hDragWnd)
{ 
m_hDragWndOwner = hDragWndOwner;
m_cxHotSpotOffset = cxHotSpotOffset;
m_cyHotSpotOffset = cyHotSpotOffset;

POINT ptDest = ptCurrentMousePos;
ClientToScreen(m_hDragWndOwner, &ptDest);

::MoveWindow(m_hDragWnd,
ptDest.x - m_cxHotSpotOffset, 
ptDest.y - m_cyHotSpotOffset, 
cxWnd,
cyWnd, TRUE);

//Draw background image for dragging support window
if(hBack)
{ HDC hDC = ::GetDC(m_hDragWnd);
HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hbmpOldMem = (HBITMAP)::SelectObject(hMemDC, hBack);

::BitBlt(hDC, 0, 
0, 
cxWnd, 
cyWnd, 
hMemDC, 
cxBackOffset, 
cyBackOffset, 
SRCCOPY);


::SelectObject(hMemDC, hbmpOldMem);
::DeleteDC(hMemDC);
::ReleaseDC(m_hDragWnd, hDC);
}
}
return m_hDragWnd != 0;
}

Third, change the position and dimensions for dragging support window by calling MoveWindow.

Fourth, move dragging support window's position far to screen. The code is like this:

BOOL CImageDragWrapper::DragEnd()
{
if(m_hDragWnd && m_hDragWndOwner)
{
m_hDragWndOwner = 0;
::MoveWindow(m_hDragWnd,
99000, 
0, 
6,
6, TRUE);
}
return m_hDragWnd != 0;
}

Using the Code

First, in InitInstance method of CWinApp's subclass, add code like this:

CImageDragWrapper::Initialize();
CTestDragDialogDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{ // TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
CImageDragWrapper::Destroy();

Then in dragging owner window's OnMouseMove, OnLButtonUp method call DragBegin, DragMove, DragEnd method of CImageDragWrapper. It's very simple. That's all.

Note: You can compare CImageDragWrapper with CImageList by using my sample code!

Points of Interest

This is my first article posted on a foreign website. I'm sorry that my English is very poor to clearly express what I think!

History

  • 2009/06/05 First submission