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

[List] List 컨트롤에 ComboBox 사용하기

by izen8 2011. 5. 4.
반응형

리스트 컨트롤 스타일중 Report 로 이용시 컬럼 내부에 콤보 박스를 넣는 방법에 대해서 소개합니다.
버튼이나 특정 이벤트를 통해서 컬럼의 값을 변경하는 것이 아닌, 콤보 박스를 이용하여 리스트 컨트롤 내부에서 컬럼의 값을 변경한다는 것은 상당히 큰 매리트가 있습니다.

 소스는 두개의 클래스로 되어있습니다. CListCtrl 을 상속받는 클래스(이하 CAdvListCtrl)와, CComboBox를 상속받는 클래스(이하 CAdvComboBox)입니다.
 CAdvListCtrl 클래스의 경우엔 CAdvComboBox에서 발생하는 주요 이벤트 (Selection 변경, 키 입력, 포커스 드롭 등)를 받아 컬럼 내용을 처리해주는데 주 목적이 있습니다. 물론 리스트 컨트롤 포커싱(마우스클릭 등 포커스가 잡혔을때)시 CAdvComboBox 를 생성 혹은 삭제 해주는 역할도 있습니다.
 CComboBox 의 경우 위에 한번 언급한 주요 이벤트 발생시 CAdvListCtrl 로 이벤트를 날려주는데 주 목적이 있습니다.

 본 소스는 ComboBox 아이템이 하드코딩 되어있는데, 조만간 손을 봐서 아이템도 사용자가 원하는데로 추가 기입이 가능하도록 할 생각입니다.
 


AdvListCtrl.h
  1. #pragma once   
  2.   
  3. class CAdvListCtrl : public CListCtrl   
  4. {   
  5.     DECLARE_DYNAMIC(CAdvListCtrl)   
  6.   
  7. public:   
  8.     CAdvListCtrl();   
  9.     virtual ~CAdvListCtrl();   
  10.   
  11.     afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);   
  12.     afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);   
  13.     afx_msg void OnLvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult);   
  14.     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);   
  15.     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);   
  16.   
  17.     int         HitTestEx(CPoint& point, int* nCol) const;   
  18.     void        SetColumnCombo(int nColumn);   
  19.   
  20. protected:   
  21.     DECLARE_MESSAGE_MAP()   
  22.   
  23.     int     m_nColumn;   
  24.     CComboBox*  ShowAdvComboBox(int nItem, int nCol, CStringList& lstItems, int nSel);   
  25. };  


AdvListCtrl.cpp
  1. #include "stdafx.h"   
  2. #include "AdvListCtrl.h"   
  3. #include "AdvComboBox.h"   
  4.   
  5. IMPLEMENT_DYNAMIC(CAdvListCtrl, CListCtrl)   
  6.   
  7. CAdvListCtrl::CAdvListCtrl()   
  8. {   
  9.     m_nColumn = -1;   
  10. }   
  11.   
  12. CAdvListCtrl::~CAdvListCtrl()   
  13. {   
  14. }   
  15.   
  16.   
  17. BEGIN_MESSAGE_MAP(CAdvListCtrl, CListCtrl)   
  18.     ON_WM_HSCROLL()   
  19.     ON_WM_VSCROLL()   
  20.     ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, &CAdvListCtrl::OnLvnEndlabeledit)   
  21.     ON_WM_LBUTTONDOWN()   
  22.     ON_WM_LBUTTONUP()   
  23. END_MESSAGE_MAP()   
  24.   
  25. void CAdvListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)   
  26. {   
  27.     if(GetFocus() != this) SetFocus();   
  28.     CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);   
  29. }   
  30.   
  31. void CAdvListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)   
  32. {   
  33.     if(GetFocus() != this) SetFocus();   
  34.     CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);   
  35. }   
  36.   
  37. void CAdvListCtrl::OnLvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult)   
  38. {   
  39.     NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);   
  40.     LVITEMW* pItem = &pDispInfo->item;   
  41.   
  42.     if(pItem->pszText != NULL)   
  43.     {   
  44.         SetItemText(pItem->iItem, pItem->iSubItem, pItem->pszText);   
  45.     }   
  46.   
  47.     *pResult = 0;   
  48. }   
  49.   
  50. void CAdvListCtrl::OnLButtonDown(UINT nFlags, CPoint point)   
  51. {   
  52.     int nIndex;   
  53.     CListCtrl::OnLButtonDown(nFlags, point);   
  54.   
  55.     int nColumn;   
  56.     if((nIndex = HitTestEx(point, &nColumn)) != -1)   
  57.     {   
  58.         UINT flag = LVIS_FOCUSED;   
  59.         if((GetItemState(nIndex, flag) & flag) == flag && m_nColumn == nColumn)   
  60.         {   
  61.             if(!(GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS))   
  62.             {   
  63.                 CStringList lstItems;   
  64.                 lstItems.AddTail(L"Item 1");   
  65.                 lstItems.AddTail(L"Item 2");   
  66.   
  67.                 CString strGet = this->GetItemText(nIndex, m_nColumn);   
  68.                 ShowAdvComboBox(nIndex, m_nColumn, lstItems, 0);   
  69.                 SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);   
  70.             }   
  71.         }   
  72.         else  
  73.         {   
  74.             SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);   
  75.         }   
  76.     }   
  77.   
  78. //  CListCtrl::OnLButtonDown(nFlags, point);   
  79. }   
  80.   
  81. void CAdvListCtrl::OnLButtonUp(UINT nFlags, CPoint point)   
  82. {   
  83. //  CListCtrl::OnLButtonUp(nFlags, point);   
  84. }   
  85.   
  86. int CAdvListCtrl::HitTestEx(CPoint& point, int* nCol) const  
  87. {   
  88.     int nColumn = 0;   
  89.     int nRow = HitTest(point, NULL);   
  90.   
  91.     if(nCol) *nCol = 0;   
  92.   
  93.     // LVS_REPORT Check   
  94.     if((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)   
  95.         return nRow;   
  96.   
  97.     nRow = GetTopIndex();   
  98.     int nBottom = nRow + GetCountPerPage();   
  99.   
  100.     if(nBottom > GetItemCount())   
  101.         nBottom = GetItemCount();   
  102.   
  103.     CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);   
  104.     int nColumnCount = pHeader->GetItemCount();   
  105.   
  106.     for(; nRow <= nBottom; ++nRow)   
  107.     {   
  108.         CRect rect;   
  109.         GetItemRect(nRow, &rect, LVIR_BOUNDS);   
  110.   
  111.         if(rect.PtInRect(point))   
  112.         {   
  113.             for(nColumn = 0; nColumn < nColumnCount; ++nColumn)   
  114.             {   
  115.                 int nColWidth = GetColumnWidth(nColumn);   
  116.                 if(point.x >= rect.left && point.x <= (rect.left + nColWidth))   
  117.                 {   
  118.                     if(nCol) *nCol = nColumn;   
  119.                     return nRow;   
  120.                 }   
  121.   
  122.                 rect.left += nColWidth;   
  123.             }   
  124.         }   
  125.     }   
  126.   
  127.     return -1;   
  128. }   
  129.   
  130. void CAdvListCtrl::SetColumnCombo(int nColumn)   
  131. {   
  132.     m_nColumn = nColumn;   
  133. }   
  134.   
  135. CComboBox* CAdvListCtrl::ShowAdvComboBox(int nItem, int nCol, CStringList& lstItems, int nSel)   
  136. {   
  137.     if(!EnsureVisible(nItem, TRUE)) return NULL;   
  138.   
  139.     CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);   
  140.     int nColumnCount = pHeader->GetItemCount();   
  141.     if(nCol >= nColumnCount || GetColumnWidth(nCol) < 10)   
  142.         return NULL;   
  143.   
  144.     int offset = 0;   
  145.     for(int i = 0; i < nCol; ++i)   
  146.     {   
  147.         offset += GetColumnWidth(i);   
  148.     }   
  149.   
  150.     CRect rect;   
  151.     GetItemRect(nItem, &rect, LVIR_BOUNDS);   
  152.   
  153.     CRect rcClient;   
  154.     GetClientRect(&rcClient);   
  155.     if(offset + rect.left < 0 || offset + rect.left > rcClient.right)   
  156.     {   
  157.         CSize size;   
  158.         size.cx = offset + rect.left;   
  159.         size.cy = 0;   
  160.         Scroll(size);   
  161.         rect.left -= size.cx;   
  162.     }   
  163.   
  164.     rect.left += offset + 4;   
  165.     rect.right = rect.left + GetColumnWidth(nCol) - 3;   
  166.     int nHeight = rect.bottom - rect.top;   
  167.     rect.bottom += 5 * nHeight;   
  168.     if(rect.right > rcClient.right) rect.right = rcClient.right;   
  169.   
  170.     DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE |   
  171.         CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL;   
  172.     CComboBox* pList = new CAdvComboBox(nItem, nCol, &lstItems, nSel);   
  173.     pList->Create(dwStyle, rect, this, IDC_ADVCOMBO);   
  174.     pList->SetItemHeight(-1, nHeight);   
  175.     pList->SetHorizontalExtent(GetColumnWidth(nCol));   
  176.   
  177.     return pList;   
  178. }  


AdvComboBox.h
  1. #pragma once   
  2.   
  3. class CAdvComboBox : public CComboBox   
  4. {   
  5.     DECLARE_DYNAMIC(CAdvComboBox)   
  6.   
  7. public:   
  8.     CAdvComboBox(int nItem, int nSubItem, CStringList* plstItems, int nSel);   
  9.     virtual ~CAdvComboBox();   
  10.   
  11.     virtual BOOL PreTranslateMessage(MSG* pMsg);   
  12.   
  13. protected:   
  14.     DECLARE_MESSAGE_MAP()   
  15.   
  16. public:   
  17.     afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);   
  18.     afx_msg void OnKillFocus(CWnd* pNewWnd);   
  19.     afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);   
  20.     afx_msg void OnNcDestroy();   
  21.     afx_msg void OnCloseUp();   
  22.   
  23. private:   
  24.     int         m_nItem;   
  25.     int         m_nSubItem;   
  26.     CStringList m_lstItems;   
  27.     int         m_nSel;   
  28.     bool        m_bESC;   
  29. };  


AdvComboBox.cpp
  1. #include "stdafx.h"   
  2. #include "AdvComboBox.h"   
  3.   
  4. IMPLEMENT_DYNAMIC(CAdvComboBox, CComboBox)   
  5.   
  6. CAdvComboBox::CAdvComboBox(int nItem, int nSubItem, CStringList* plstItems, int nSel)   
  7. : m_nItem(nItem)   
  8. , m_nSubItem(nSubItem)   
  9. , m_nSel(nSel)   
  10. , m_bESC(false)   
  11. {   
  12.     m_lstItems.AddTail(plstItems);   
  13. }   
  14.   
  15. CAdvComboBox::~CAdvComboBox()   
  16. {   
  17. }   
  18.   
  19.   
  20. BEGIN_MESSAGE_MAP(CAdvComboBox, CComboBox)   
  21.     ON_WM_CREATE()   
  22.     ON_WM_KILLFOCUS()   
  23.     ON_WM_CHAR()   
  24.     ON_WM_NCDESTROY()   
  25.     ON_CONTROL_REFLECT(CBN_CLOSEUP, OnCloseUp)   
  26. END_MESSAGE_MAP()   
  27.   
  28. BOOL CAdvComboBox::PreTranslateMessage(MSG* pMsg)   
  29. {   
  30.     if(pMsg->message == WM_KEYDOWN)   
  31.     {   
  32.         if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)   
  33.         {   
  34.             ::TranslateMessage(pMsg);   
  35.             ::DispatchMessage(pMsg);   
  36.   
  37.             return TRUE;   
  38.         }   
  39.     }   
  40.   
  41.     return CComboBox::PreTranslateMessage(pMsg);   
  42. }   
  43.   
  44. int CAdvComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct)   
  45. {   
  46.     if (CComboBox::OnCreate(lpCreateStruct) == -1)   
  47.         return -1;   
  48.   
  49.     CFont* pFont = GetParent()->GetFont();   
  50.     SetFont(pFont);   
  51.   
  52.     for(POSITION pos = m_lstItems.GetHeadPosition(); pos != NULL; )   
  53.     {   
  54.         AddString((LPCTSTR)(m_lstItems.GetNext(pos)));   
  55.     }   
  56.     SetCurSel(m_nSel);   
  57.     SetFocus();   
  58.   
  59.     return 0;   
  60. }   
  61.   
  62. void CAdvComboBox::OnKillFocus(CWnd* pNewWnd)   
  63. {   
  64.     CComboBox::OnKillFocus(pNewWnd);   
  65.   
  66.     CString strTemp;   
  67.     GetWindowText(strTemp);   
  68.   
  69.     LV_DISPINFO dispinfo;   
  70.     dispinfo.hdr.hwndFrom   = GetParent()->m_hWnd;   
  71.     dispinfo.hdr.idFrom     = GetDlgCtrlID();   
  72.     dispinfo.hdr.code       = LVN_ENDLABELEDIT;   
  73.   
  74.     dispinfo.item.mask      = LVIF_TEXT;   
  75.     dispinfo.item.iItem     = m_nItem;   
  76.     dispinfo.item.iSubItem  = m_nSubItem;   
  77.     dispinfo.item.pszText   = m_bESC ? NULL : LPTSTR((LPCTSTR)strTemp);   
  78.     dispinfo.item.cchTextMax= strTemp.GetLength();   
  79.   
  80.     GetParent()->GetParent()->SendMessage(WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM)&dispinfo);   
  81.   
  82.     PostMessage(WM_CLOSE);   
  83. }   
  84.   
  85. void CAdvComboBox::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)   
  86. {   
  87.     if(nChar == VK_ESCAPE || nChar == VK_RETURN)   
  88.     {   
  89.         if(nChar == VK_ESCAPE)   
  90.         {   
  91.             m_bESC = true;   
  92.         }   
  93.         GetParent()->SetFocus();   
  94.         return;   
  95.     }   
  96.   
  97.     CComboBox::OnChar(nChar, nRepCnt, nFlags);   
  98. }   
  99.   
  100. void CAdvComboBox::OnNcDestroy()   
  101. {   
  102.     CComboBox::OnNcDestroy();   
  103.   
  104.     delete this;   
  105. }   
  106.   
  107. void CAdvComboBox::OnCloseUp()   
  108. {   
  109.     GetParent()->SetFocus();   
반응형

댓글