리스트 컨트롤 안에서 드래그 앤 드롭 구현하기.

드래그 이미지는 CListCtrl 클래스의 CreateDragImage() 메서드를 이용해 만들며, 이것은 리스트 컨트롤이나 트리 컨트롤의 이미지 목록과 관련이 깊다. CImageList 클래스는 드래그 이미지를 만드는 역활을 하는 메서드를 제공하며, CWnd 클래스도 드래그와 관련된 메서드를 제공한다. 다음은 다이얼로그 베이스에서 구현한 예제 소스다.

----------------- OnInitDialog() ------------------------------------------------------------------

 CBitmap Bmp;
 Bmp.LoadBitmap(IDB_ImageList);

 static CImageList ImgList;
 ImgList.Create(32,32, ILC_COLOR32 | ILC_MASK, 5, 0);
 ImgList.Add(&Bmp, RGB(0,0,0));
 m_List_Left.SetImageList(&ImgList, LVSIL_NORMAL);
 m_List_Right.SetImageList(&ImgList, LVSIL_NORMAL); //리스트 컨트롤끼리 이미지리스트를 공유한다.
 //그러므로 Share Image Lists 속성을 True로 설정해야 한다.

 CString strItem = _T("");
 for(int i=0; i<5; ++i)
 {
  strItem.Format(_T("%dth Item"), i);
  m_List_Left.InsertItem(i, strItem, i); //이미지리스트를 이용해서 인썰트!!
 }

 DWORD dwExStyle = m_List_Left.GetExtendedStyle();
 m_List_Left.SetExtendedStyle(dwExStyle | LVS_EX_BORDERSELECT);

 dwExStyle = m_List_Right.GetExtendedStyle();
 m_List_Right.SetExtendedStyle(dwExStyle | LVS_EX_BORDERSELECT);

-------------------------------------------------------------------------------------




void CDragDemoDlg::OnLvnBegindragListLeft(NMHDR *pNMHDR, LRESULT *pResult)
{
 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
 
 CPoint ptDrag, ptAction; //ptDrag 는 드래그 시작위치   
 m_nIndexLeftSel = pNMLV->iItem; //드래그가 시작된 항목의 인덱스를 저장, 이후 LBUTTONUP 에서 활용
 
 // 1, 선택된 아이템, 2, 드래그 시작점에 드래그이미지를 만든다.
 // POINT 구조체에 그 항목의 리스트 컨트롤 기준 좌표를 반환하며,
 // 아래 함수는 내부적으로 new 연산으로 CImageList를 생성하므로 드래그가 끝날 때 delete 연산으로 소멸해야 한다.

m_pImgListDrag = m_List_Left.CreateDragImage(pNMLV->iItem, &ptDrag); 

 m_pImgListDrag->SetBkColor(RGB(0,0,0));
 ptAction = pNMLV->ptAction; //리스트 컨트롤에서 드래그를 시작한 좌표(리스트컨트롤 기준 좌표)가 들어간다.

 SetCapture(); //마우스 캡쳐, 다른창에 넘어가도 문제없게 하기위해서 사용
 m_pImgListDrag->BeginDrag(0,ptAction - ptDrag);
 //1, 화면에 출력할 드래그 이미지의 인덱스,
 //2, 그 이미지에서 마우스 포인터에 맞추어야 할 좌표
 
 m_List_Left.ClientToScreen(&ptAction); //스크린 좌표로 바꾼다
 m_pImgListDrag->DragEnter(NULL, ptAction);  //드래그 상태로 변경하며, 반투명한 드래그 이미지를 출력.
 //1, 이 값을 리스트 컨트롤이 아니라, NULL로 설정하면 바탕화면이 되므로,
 //2, 두번째 인자로 전달되는 좌표는 스크린 기준 좌표가 되어야 하고, 이 좌표에 드래그 이미지 출력


 
 *pResult = 0;
}

void CDragDemoDlg::OnMouseMove(UINT nFlags, CPoint point)
{
 //대화상자 기준의 좌표로 마우스 좌표가 들어오므로 ClienToScreen() 으로 변환해야한다.

 if(m_pImgListDrag != NULL)
 {
  ClientToScreen(&point);

  CWnd* pWnd = CWnd::WindowFromPoint(point); //point 좌표에 해당하는 윈도우 객체의 주소를 구한다.
  // 이 후 이 주소가 대화 상자 자체이거나, 자식 윈도우에 해당하는 주소면 드래그 상태를 유지해라.
  if(pWnd != NULL)
  {
   if(this == pWnd || IsChild(pWnd))
   {
    m_pImgListDrag->DragEnter(NULL, point);
    m_pImgListDrag->DragMove(point);
   }else //대화상자가 아니거나, 자식 윈도우가 아니면 드래그하지마라.
   {
    m_pImgListDrag->DragLeave(NULL); //드래그 이미지를 지운다. 다시 나오게 하려면 DragEnter() 를 다시 호출하면된다
   }
  }

 }
 CDialog::OnMouseMove(nFlags, point);
}

void CDragDemoDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
 
 CString strTmp = _T("");
 if(m_pImgListDrag != NULL)
 {
  ClientToScreen(&point);
  m_pImgListDrag->DragLeave(NULL);
  m_pImgListDrag->EndDrag();
  ReleaseCapture();

  //오른쪽 리스트에 아이템추가하기
  CWnd* pWnd = CWnd::WindowFromPoint(point);
  if(pWnd == &m_List_Right && m_nIndexLeftSel >= 0)
  {
   LVITEM lvItem;
   TCHAR szBuffer[256];
   ::ZeroMemory(&lvItem, sizeof(lvItem));
   ::ZeroMemory(szBuffer, sizeof(szBuffer));

   lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
   lvItem.iItem = m_nIndexLeftSel;
   lvItem.pszText = szBuffer;
   lvItem.cchTextMax = 256;
   m_List_Left.GetItem(&lvItem);

   m_List_Right.InsertItem(0, lvItem.pszText , lvItem.iImage);
  }else //왼쪽 리스트이면 리스트안의 어디에 놓았는지 구체적인 아이템 인덱스 출력
  {
   m_List_Left.ScreenToClient(&point);

   //HitText() 함수는 인자로 전달받은 좌표에 해당항목있는지 검사후 인덱스를 반환한다. 아주 중요하다.
   int nIndex = m_List_Left.HitTest(point);
   if(nIndex >= 0)
   {
    strTmp.Format(_T("Drop on %dth Item"), nIndex);
    AfxMessageBox(strTmp);

   }

  }

  delete m_pImgListDrag; //소멸하는 것은 드래그이미지를 삭제한다는 뜻.
  m_pImgListDrag = NULL; //다시 초기화
  m_nIndexLeftSel = -1;  //다시 초기화

  /* 이것들을 손에 익을때까지 연속적으로 반복 숙달할 것! */
 }
 CDialog::OnLButtonUp(nFlags, point);
}

'Windows > MFC' 카테고리의 다른 글

Modal, Modeless 대화상자, 공용 대화상자  (0) 2011.11.19
탭 컨트롤  (0) 2011.11.18
트리 컨트롤 ( CTreeCtrl )  (0) 2011.11.18
이미지 프로세싱  (0) 2011.11.15
RGB 와 CMYK, HSV, HLS  (0) 2011.11.15

+ Recent posts