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

  • 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 …

  • For many organizations, moving enterprise applications to the public cloud can be a very attractive proposition, but planning the best way to move your applications is mission–critical. As an alternative to the costly option of re–architecting the application for a cloud environment, you can follow a "lift and shift" model that's significantly cheaper and almost always a lot quicker. In order to have a successful "lift and shift" migration, read this white paper to learn a few rules you should …

Most Popular Programming Stories

More for Developers

RSS Feeds

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