Overcome Window Flicker While Dragging

While I use the CImageList control for dragging, I found it flickers in the owner window while draging and redraw the client region. I tried Google to find a solution, but there were no result, so I try to solve it myself.

Here's my solution, which I'm very glad share with you!

First, you should register a new window class and create a new top most tool window, and move it's position far off screen(I take 99000), so it's not visible. The code would look 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 the window to properly position and paint it's client. The code would look 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, changes the position and dimensions for dragging support window by calling MoveWindow

Forth, move dragging to support the window's postion far to screen. The code would look 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 the 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 the owner window's OnMouseMove, OnLButtonUp method calls DragBegin, DragMove, and DragEnd method of CImageDragWrapper, It's very simple.

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



About the Author

Jehhry23 Lv

I'm come from china, very glad to make friend with you!

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • This IDC study assists senior IT leaders in assessing the current state of their hybrid cloud management processes, governance models, technologies, and skills to identify gaps and create a road map for better aligning the organization's management model and tools with the emerging needs of complex, dynamic self-service hybrid cloud environments. This IDC MaturityScape identifies five maturity stages for hybrid cloud management based on a set of specific people, process, and technology dimensions and outcomes. …

  • Speed. Agility. Flexibility. There are the big drivers behind most organizations' move to the cloud for their test/dev environments. Freed from the shackles of physical, on-premises infrastructures means test/dev teams can be incredibly fast, both in standing up and tearing down test beds. They can manage version control and they can share work between teams faster ever than below. Read this white paper to learn how your business can respond faster to the rapidly changing needs of customers with a cloud-based …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date