본문 바로가기
C & C++/MFC 컨트롤

[List] List 컨트롤 원하는 항목 수정

by izen8 2011. 5. 4.
반응형


ListControl은 MFC에서 굉장히 유용히 쓰이는 컨트롤입니다.
해당 컨트롤에서 직접 원하는 위치를 즉석 수정하기 위한 컨트롤을 만들었습니다.

아마 그냥 유용하게 쓰일듯 싶기도 해서 포스팅.

EditListCtrl.h
  1. #pragma once   
  2.   
  3.   
  4. // CEditListCtrl   
  5.   
  6. class CEditListCtrl : public CListCtrl   
  7. {   
  8.     DECLARE_DYNAMIC(CEditListCtrl)   
  9.   
  10. public:   
  11.     CEditListCtrl();   
  12.     virtual ~CEditListCtrl();   
  13.   
  14. protected:   
  15.     DECLARE_MESSAGE_MAP()   
  16.   
  17. public:   
  18.     virtual BOOL PreTranslateMessage(MSG* pMsg);   
  19.     afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);   
  20.   
  21.     // 초기화 함수.   
  22.     void Init(void);   
  23.   
  24.     // CEditListCtrl 을 사용하는 Dialog 의 OnOK 함수가 호출될때 호출해야 한다.   
  25.     void OnOK(void);   
  26.   
  27.     // List 값을 바꾼다.   
  28.     BOOL SetText(CString _val, int _row, int _col);   
  29.   
  30. protected:   
  31.     // ListCtrl 을 클릭했을때 nItem 저장될 변수. (Row)   
  32.     int m_nItem;   
  33.   
  34.     // ListCtrl 을 클릭했을때 nSubItem 저장될 변수 (Col);   
  35.     int m_nSubItem;   
  36.   
  37.     // 현재 포커스가 어딘지 확인하는 변수   
  38.     HWND m_hFocus;   
  39.   
  40.     bool m_bInit;   
  41.   
  42.     HWND _GetEditHwnd(void);   
  43.     HWND _GetListHwnd(void);   
  44.     HWND _GetParentHwnd(void);   
  45. };  


EditListCtrl.cpp
  1. // EditListCtrl.cpp : 구현 파일입니다.   
  2. //   
  3.   
  4. #include "stdafx.h"   
  5. #include "TestApp.h"   
  6. #include "EditListCtrl.h"   
  7.   
  8.   
  9. // CEditListCtrl   
  10.   
  11. IMPLEMENT_DYNAMIC(CEditListCtrl, CListCtrl)   
  12.   
  13. CEditListCtrl::CEditListCtrl()   
  14. : m_nItem(0), m_nSubItem(0)   
  15. , m_bInit(false)   
  16. , m_hFocus((HWND)0)   
  17. {   
  18.   
  19. }   
  20.   
  21. CEditListCtrl::~CEditListCtrl()   
  22. {   
  23. }   
  24.   
  25. BEGIN_MESSAGE_MAP(CEditListCtrl, CListCtrl)   
  26.     ON_NOTIFY_REFLECT(NM_CLICK, &CEditListCtrl::OnNMClick)   
  27. END_MESSAGE_MAP()   
  28.   
  29.   
  30.   
  31.   
  32. // CEditListCtrl 메시지 처리기입니다.   
  33.   
  34. BOOL CEditListCtrl::PreTranslateMessage(MSG* pMsg)   
  35. {   
  36.     if(m_hFocus != (HWND)0)   
  37.     {   
  38.         HWND hFocus = ::GetFocus();   
  39.   
  40.         // Edit 가 Focus를 잃으면.   
  41.         if(m_hFocus != hFocus)   
  42.         {   
  43.             OnOK();   
  44.         }   
  45.     }   
  46.        
  47.   
  48.     return CListCtrl::PreTranslateMessage(pMsg);   
  49. }   
  50.   
  51. void CEditListCtrl::Init(void)   
  52. {   
  53.     if(m_bInit) return;   
  54.   
  55.     SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);   
  56.     ::ShowWindow(_GetEditHwnd(), SW_HIDE);   
  57.   
  58.     m_bInit = true;   
  59. }   
  60.   
  61.   
  62. // Return 키가 눌렸을때 호출하기 위한..   
  63. void CEditListCtrl::OnOK(void)   
  64. {   
  65.     CWnd* pWnd = GetFocus();   
  66.   
  67.     if(_GetEditHwnd() == pWnd->GetSafeHwnd() ||   
  68.         _GetEditHwnd() == m_hFocus)   
  69.     {   
  70.         // EditCtrl로 부터 Text를 얻어온다.   
  71.         wchar_t cText[255];   
  72.         ZeroMemory(cText, 255);   
  73.         ::GetWindowText(_GetEditHwnd(), cText, 255);   
  74.         CString cStrText(cText);   
  75.   
  76.         // 얻어온 텍스트를 ListCtrl 에 적용시킨다   
  77.         if(SetText(cStrText, m_nItem, m_nSubItem) == FALSE)   
  78.             return;   
  79.   
  80.         // EditCtrl의 Focus를 죽인다.   
  81.         ::SendMessage(_GetEditHwnd(), WM_KILLFOCUS, 0, 0);   
  82.         ::ShowWindow(_GetEditHwnd(), SW_HIDE);   
  83.         ::SetFocus(pWnd->GetSafeHwnd());   
  84.   
  85.         // ListCtrl의 SelectionMark를 지정한다.   
  86.         SetSelectionMark(m_nItem);   
  87.     }   
  88.   
  89.     m_hFocus = (HWND)0;   
  90. }   
  91.   
  92. BOOL CEditListCtrl::SetText(CString _val, int _row, int _col)   
  93. {   
  94.     return SetItemText(_row, _col, _val);   
  95. }   
  96.   
  97. void CEditListCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)   
  98. {   
  99.     Invalidate();   
  100.   
  101.     LPNMITEMACTIVATE pNMITEM = (LPNMITEMACTIVATE) pNMHDR;   
  102.     m_nItem = pNMITEM->iItem;   
  103.     m_nSubItem = pNMITEM->iSubItem;   
  104.   
  105.     // 선택된 지점이 올바르지 않을시...   
  106.     if(m_nSubItem == 0 || m_nSubItem == -1 || m_nItem == -1)   
  107.         return;   
  108.   
  109.     // 선택된 SubItem의 Text를 CEdit 에 넣어주기 위한 변수   
  110.     CString cStrText = GetItemText(m_nItem, m_nSubItem);   
  111.   
  112.     CRect rtSubItem, rtListCtrl, rtDlg;   
  113.     // SubItem 의 Rect를 얻어온다.   
  114.     if(GetSubItemRect(pNMITEM->iItem, pNMITEM->iSubItem, LVIR_BOUNDS, rtSubItem) == FALSE)   
  115.         return;   
  116.   
  117.     // ListControl 의 Window Bounds 를 얻어온다.   
  118.     ::GetWindowRect(_GetListHwnd(), &rtListCtrl);   
  119.   
  120.     // Parent Dialog 의 Windows Bounds 를 얻어온다.   
  121.     ::GetWindowRect(_GetParentHwnd(), &rtDlg);   
  122.   
  123.     // Dialog에 위치한 ListCtrl의 left & top 위치를 구한다.   
  124.     int nThisLeft = rtListCtrl.left - rtDlg.left;   
  125.     int nThisTop = rtListCtrl.top - rtDlg.top;   
  126.   
  127.     // EditCtrl의 위치를 변경해준다.   
  128.     ::SetWindowPos(   
  129.         _GetEditHwnd(),    
  130.         HWND_TOP,   
  131.         nThisLeft + rtSubItem.left + 7,   
  132.         nThisTop + rtSubItem.top + 4,   
  133.         rtSubItem.Width() - 7,   
  134.         rtSubItem.Height() - 4,   
  135.         NULL);   
  136.   
  137.     // EditCtrl Show   
  138.     ::ShowWindow(_GetEditHwnd(), SW_SHOW);   
  139.     ::SetFocus(_GetEditHwnd());   
  140.   
  141.     // SubItem 위치에 외각선을 그려준다.   
  142.     ::Rectangle(::GetDC(_GetListHwnd()), rtSubItem.left, rtSubItem.top - 1, rtSubItem.right, rtSubItem.bottom);   
  143.   
  144.     // EditCtrl 에 선택한 List의 Text 를 넣어준다.   
  145.     ::SetWindowText(_GetEditHwnd(), cStrText);   
  146.   
  147.     // 삽입한 Text의 마지막에 포커스를 맞춰주고 Mark한다.   
  148.     int nSel = cStrText.GetLength();   
  149.     ::SendMessage(_GetEditHwnd(), EM_SETSEL, LOWORD(nSel), HIWORD(nSel));   
  150.   
  151.     // Focus를 잃었을 경우 ListCtrl에 적용시키기 위해 저장   
  152.     m_hFocus = _GetEditHwnd();   
  153.     Invalidate();   
  154.   
  155.     *pResult = 0;   
  156. }   
  157.   
  158.   
  159. HWND CEditListCtrl::_GetEditHwnd(void)   
  160. {   
  161.     return ::GetDlgItem(GetParent()->GetSafeHwnd(), IDC_EDIT_CAM_ATTR);   
  162. }   
  163.   
  164. HWND CEditListCtrl::_GetListHwnd(void)   
  165. {   
  166.     return GetSafeHwnd();   
  167. }   
  168.   
  169. HWND CEditListCtrl::_GetParentHwnd(void)   
  170. {   
  171.     return GetParent()->GetSafeHwnd();   
  172. }  



이 컨트롤을 가지는 Dialog Class의 PreTranslateMessage 부분 혹은 OnOK 부분 (Return키 작동시를 위한)에
현재 포커스가 ListCtrl 혹은 EditCtrl 일 경우 CEditListCtrl 의 OnOK 함수를 호출해야 합니다.

  1. CTestDlg::OnOK()   
  2. {   
  3.     int id = GetFocus()->GetDlgCtrlID();   
  4.     if(id == IDC_LIST_EDITLISTCTRL || id == IDC_EDIT_EDITLISTCTRL)   
  5.         m_editListCtrl.OnOK()   
  6. }  


이정도가 되겠습니다
반응형

댓글