6.4 ÇϺξÆÀÌÅÛ ÆíÁýÀ» À§ÇØ µå·Ó´Ù¿î ¸®½ºÆ® »ç¿ëÇϱâ

¶§¶§·Î, »ç¿ëÀÚ°¡ ¸¶À½´ë·Î ¾ÆÀÌÅÛÀ» ÆíÁýÇϰÔÇϴ°ͺ¸´Ù, »ç¿ëÀÚ¿¡°Ô ¼±ÅðªµéÀ»Áִ°ÍÀÌ ÁÁÀ»¼öµµ ÀÖ½À´Ï´Ù. ¿¡µð
Æ® ÄÁÆ®·Ñ´ë½Å µå·Ó´Ù¿î ¸®½ºÆ®¸¦ »ç¿ëÇÔÀ¸·Î½áÀ̰ÍÀÌ °¡´ÉÇÕ´Ï´Ù. ±¸ÇöÇÏ·Á¸é, ÇϺξÆÀÌÅÛÆíÁý°ú °°Àº ÆÐÅÏÀ» µû¸¨
´Ï´Ù.

<±×¸²>

´Ü°è 1:         CListCtrl »ó¼ÓŬ·¡½º »ý¼º
                   CListCtrl ·Î ºÎÅÍ »õ·Î¿î Ŭ·¡½º¸¦ ÆÄ»ýÇϰųª Á¸ÀçÇÏ´Â ¼­ºêŬ·¡½º¿¡ ¼öÁ¤À» ÇÕ´Ï´Ù. ¸¸¾à ÀÌ¹Ì 6.3¿¡¼­ ¼³¸íÇÑ ÇϺξÆÀÌÅÛ ÆíÁýÀÌ °¡´ÉÇÑ Å¬·¡½º¸¦ »ç¿ëÇÑ´Ù¸é±× Ŭ·¡½º¸¦ »ç¿ëÇÒ¼ö ÀÖ½À´Ï´Ù.

´Ü°è 2:         HitTestEx() ÇÔ¼ö Á¤ÀÇ
                CMyListCtrl Ŭ·¡½º¿¡ È®ÀåµÈ HitTest ÇÔ¼ö¸¦ Á¤ÀÇÇÕ´Ï´Ù. ÀÌ ÇÔ¼ö´Â Ŭ¸¯ÇÑ Á¡ÀÇ Row À妽º¿Í Ä÷³À» °áÁ¤ÇÒ°ÍÀÔ´Ï´Ù. HitTestEx() ÇÔ¼ö´Â ÀÌ¹Ì 4.4 ¿¡¼­ »ìÆìº¸¾Ò½À´Ï´Ù. Ŭ¸¯À̳ª ´õºíŬ¸¯½Ã ÆíÁýÀÌ ½ÃÀ۵ǵµ·Ï ÀÌ ÇÔ¼ö¸¦ ÇÊ¿ä·Î ÇÕ´Ï´Ù.

´Ü°è 3: µå·Ó´Ù¿î ¸®½ºÆ®¸¦ »ý¼ºÇÏ´Â ÇÔ¼ö¸¦ ÀÛ¼ºÇÕ´Ï´Ù.
                ÀÌ ÇÔ¼ö´Â 6.3¿¡¼­ ¼³¸íÇß´ø EditSubLabel() ÇÔ¼ö¿Í ¸Å¿ì ºñ½ÁÇÕ´Ï´Ù. Â÷ÀÌÁ¡Àº ¸¶Áö¸·¿¡ CInPlaceList Ŭ·¡½º·ÎºÎÅÍ ÄÞº¸¹Ú½º¸¦ ¸¸µç´Ù´Â°ÍÀÔ´Ï´Ù. À̰ÍÀº ÀÎÀڷι®ÀÚ¿­µéÀÇ ¸®½ºÆ®¸¦ ÇÊ¿ä·Î ÇѴٴ°ÍÀ» ÁÖÀÇÇϽʽÿÀ. ÀÌ ¸®½ºÆ®´Â µå·Ó´Ù¿î¸®½ºÆ®¸¦ ä¿ì±â À§ÇØ ÇÊ¿äÇÕ´Ï´Ù. ¸¶Áö¸·ÀÎÀÚ´Â ±âº»ÀûÀ¸·Î ¼±ÅÃµÉ ¾ÆÀÌÅÛÀÇ ¹øÈ£ÀÔ´Ï´Ù.

// ShowInPlaceList              - ¸®½ºÆ®ºäÀÇ ¾Æ¹«¼¿¿¡³ª µå·Ó´Ù¿î¸®½ºÆ® »ý¼º
// Returns              - ÄÞº¸¹Ú½º¿¡ ´ëÇÑ Àӽà Æ÷ÀÎÅÍ
// nItem                - ÆíÁýÇÒ ¾ÆÀÌÅÛÀÇ ·Î¿ì À妽º
// nCol                 - ÆíÁýÇÒ ¾ÆÀÌÅÛÀÇ Ä÷³ À妽º
// lstItems             - ÄÁÆ®·ÑÀ» ä¿ï ½ºÆ®¸µÀÇ ¸®½ºÆ®
// nSel                 - ±âº»ÀûÀ¸·Î ¼±ÅÃµÉ ¾ÆÀÌÅÛÀÇ ¹øÈ£

CComboBox* CMyListCtrl::ShowInPlaceList( int nItem , int nCol ,   CStringList &lstItems, int nSel )
{
        // ¸®ÅÏµÈ Æ÷ÀÎÅÍ´Â ÀúÀåµÇ¸é ¾ÈµÊ(Save)

        // ¾ÆÀÌÅÛÀÌ º¸ÀÌ´ÂÁö È®ÀÎ
        if( !EnsureVisible( nItem, TRUE ) ) return NULL;
        
        // nCol ÀÌ À¯È¿ÇÑÁö È®ÀÎ
        CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);    
        int nColumnCount = pHeader->GetItemCount();
        if( nCol >= nColumnCount || GetColumnWidth(nCol) < 10 ) return NULL;

        // Ä÷³ ¿ÀÇÁ¼Â(Offset) °¡Á®¿À±â
        int offset = 0;
        for( int i = 0; i < nCol; i++ ) offset += GetColumnWidth( i );

        CRect rect;
        GetItemRect( nItem, &rect, LVIR_BOUNDS );

        // Ä÷³À» º¸À̱â À§ÇØ ÇÊ¿äÇÏ¸é ½ºÅ©·ÑÇÑ´Ù.
        CRect rcClient;
        GetClientRect( &rcClient );
        if( offset + rect.left < 0 || offset + rect.left > rcClient.right )     {
                CSize size;
                size.cx = offset + rect.left;
                size.cy = 0;
                Scroll( size );
                rect.left -= size.cx;
        }

        rect.left += offset+4;
        rect.right = rect.left + GetColumnWidth( nCol ) - 3;    
        int height = rect.bottom-rect.top;
        rect.bottom += 5*height;
        if( rect.right > rcClient.right)    rect.right = rcClient.right;
        DWORD dwStyle =         WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL
                                                |CBS_DROPDOWNLIST|CBS_DISABLENOSCROLL;
        CComboBox *pList = new CInPlaceList(nItem, nCol, &lstItems, nSel);
        pList->Create( dwStyle, rect, this, IDC_IPEDIT );
        pList->SetItemHeight( -1, height);
        pList->SetHorizontalExtent( GetColumnWidth( nCol ));
        return pList;
}

´Ü°è 4:         ½ºÅ©·Ñ ¸Þ½ÃÁö ó¸®Çϱâ ( Handle the scroll messages )
                CInPlaceListŬ·¡½º´Â Æ÷Ä¿½º¸¦ ÀÒ¾úÀ»¶§ µå·Ó´Ù¿î¸®½ºÆ® ÄÁÆ®·ÑÀ» ÆÄ±«ÇÏ°í °´Ã¼¸¦¾ø¾Ö±âÀ§ÇØ ¸¸µé¾î Á³½À´Ï´Ù. ¸®½ºÆ®ºäÀÇ ½ºÅ©·Ñ¹Ù¸¦ Ŭ¸¯Çϴ°ÍÀº ¸®½ºÆ® ÄÁÆ®·Ñ¿¡¼­ Æ÷Ä¿½º¸¦ »°Áö ¾Ê½À´Ï´Ù. ±×·¯¹Ç·Î ¿ì¸®´Â ¸®½ºÆ®ºä ÄÁÆ®·Ñ¿¡ Æ÷Ä¿½º¸¦ ÁÜÀ¸·Î½á Æ÷Ä¿½º¸¦ ¸®½ºÆ® ÄÁÆ®·Ñ¿¡¼­ »©¾Ò±â´Â °ÍÀ» ¹æÁöÇÏ´Â ½ºÅ©·Ñ¹Ù ¸Þ½ÃÁö¿¡ ´ëÇÑ Çڵ鷯¸¦ ÀÛ¼ºÇØ¾ß ÇÕ´Ï´Ù.

void CMyListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
        if( GetFocus() != this ) SetFocus();
        CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
        if( GetFocus() != this ) SetFocus();
        CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

´Ü°è 5:         EndLabelEdit ó¸®
                ³»Àå ¿¡µðÆ® ÄÁÆ®·Ñó·³, ¿ì¸®ÀÇ µå·Ó´Ù¿î ¸®½ºÆ® ÄÁÆ®·Ñµµ »ç¿ëÀÚ°¡ ¾ÆÀÌÅÛÀ» ¼±ÅÃÇßÀ»¶§ LVN_ENDLABELEDIT ÅëÁö¸¦ º¸³À´Ï´Ù. ¸¸¾à ÀÌ ÅëÁö ¸Þ½ÃÁö°¡ ÀÌ¹Ì Ã³¸®µÇÁö¾Ê¾Ò´Ù¸é, º¯°æ»çÇ×ÀÌ ¹Þ¾Æµé¿©Áú ¼ö ÀÖµµ·Ï Çڵ鷯¸¦ Ãß°¡ÇÕ´Ï´Ù.

void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
        LV_DISPINFO     *plvDispInfo = (LV_DISPINFO *)pNMHDR;
        LV_ITEM         *plvItem = &plvDispInfo->item;
        if (plvItem->pszText != NULL)   {
                SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);    
        }
        *pResult = FALSE;
}

´Ü°è 6:         »ç¿ëÀÚ°¡ ÆíÁýÀ» ½ÃÀÛÇÒ¼ö ÀÖµµ·Ï ÇÏ´Â ¹æ¹ýÀ» Ãß°¡ÇÕ´Ï´Ù.
                ¾Æ·¡ÄÚµå´Â WM_LBUTTONDOWN ¸Þ½ÃÁö¿¡ ´ëÇÑ Çڵ鷯ÀÔ´Ï´Ù. Æ÷Ä¿½º°¡ ÀÖ´Â ¾ÆÀÌÅÛÀÇ ¼­ºê¾ÆÀÌÅÛÀÌ Å¬¸¯µÇ¾úÀ» ¶§ µå·Ó´Ù¿î ¸®½ºÆ® ÄÁÆ®·ÑÀ» »ý¼ºÇÕ´Ï´Ù. ÀÌ ÄÚµå´Â µå·Ó´Ù¿î ¸®½ºÆ® ÄÁÆ®·ÑÀ» ¸¸µé±â Àü¿¡ ¸ÕÀú LVS_EDITLABELS ½ºÅ¸ÀÏÀ» üũÇÕ´Ï´Ù. ¹°·Ð, À̰ÍÀº ¸Å¿ì °£´ÜÇÑ ±¸ÇöÀ̹ǷΠÇʿ信 µû¶ó ¼öÁ¤µÉ Çʿ䰡 ÀÖ½À´Ï´Ù.

void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
        int index;
        CListCtrl::OnLButtonDown(nFlags, point);

        int colnum;
        if( ( index = HitTestEx( point, &colnum )) != -1 )      {
                UINT flag = LVIS_FOCUSED;
                if( (GetItemState( index, flag ) & flag) == flag )              {
                        // LVS_EDITLABELS ¿¡ ´ëÇÑ Ã¼Å©
                        if( GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS ) {
                                CStringList lstItems;
                                lstItems.AddTail( "First Item");
                                lstItems.AddTail( "Second Item");
                                lstItems.AddTail( "Third Item");
                                lstItems.AddTail( "Fourth Item");
                                lstItems.AddTail( "Fifth Item");
                                lstItems.AddTail( "Sixth Item");
                                ShowInPlaceList( index, colnum, lstItems, 2 );
                        }
                } else {
                        SetItemState(index, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED);
                }
        }
}

´Ü°è 7:         CComboBox Ŭ·¡½º ¼­ºêŬ·¡½Ì
                ¿ì¸®ÀÇ Æ¯º°ÇÑ ¿ä±¸»çÇ×À» Á¦°øÇϱâÀ§ÇØ CComboBoxŬ·¡½º¸¦ ¼­ºêŬ·¡½ÌÇØ¾ß ÇÕ´Ï´Ù.
ÀÌ Å¬·¡½º¿¡ ´ëÇÑ ÁÖ¿ä ¿ä±¸»çÇ×Àº ¾Æ·¡¿Í °°½À´Ï´Ù.

- À¯Àú°¡ ¾ÆÀÌÅÛ ¼±ÅÃÀ» ³¡³ÂÀ»½Ã LVN_ENDLABELEDIT ¸Þ½ÃÁö¸¦ º¸³»¾ß ÇÑ´Ù.
- ÆíÁýÀÌ ³¡³µÀ»¶§ ÀÚ±âÀÚ½ÅÀ» ÆÄ±«ÇØ¾ß ÇÑ´Ù.
- »ç¿ëÀÚ°¡ ESC ¶Ç´Â ¿£ÅÍ۸¦ ´©¸£°Å³ª À¯Àú°¡ ¾ÆÀÌÅÛÀ» ¼±ÅÃÇßÀ»¶§, ÄÁÆ®·ÑÀÌ   ÀÔ·Â Æ÷Ä¿½º¸¦ ÀÒÀ»¶§ ÆíÁýÀÌ ³¡³ª¾ßÇÑ´Ù.

Çì´õÆÄÀÏÀº ±¸ÇöÈ­ÀÏ(Implementation File)¾Õ¿¡ ÀÖ½À´Ï´Ù. CInPlaceList´Â 5°³ÀÇPrivate º¯¼ö¸¦ ¼±¾ðÇÕ´Ï´Ù. À̵éÀº µå·Ó´Ù¿î ¸®½ºÆ®¸¦ ÃʱâÈ­ÇÒ¶§¿Í LVN_ENDLABELEDIT ÅëÁö¸¦ º¸³¾¶§ »ç¿ëµË´Ï´Ù.

// InPlaceList.h : header file
// CInPlaceList window

class CInPlaceList : public CComboBox   {
        public: // Construction
        CInPlaceList(int iItem, int iSubItem, CStringList *plstItems, int nSel);
        public: // Attributes
        public: // Operations
        
        // Overrides
    // ClassWizard generated virtual function overrides    
        //{{AFX_VIRTUAL(CInPlaceList)
    public:
        virtual BOOL PreTranslateMessage(MSG* pMsg);
    //}}AFX_VIRTUAL

        // Implementation
        public: 
                virtual ~CInPlaceList();

        protected:              // Generated message map functions
    //{{AFX_MSG(CInPlaceList)
                afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
                afx_msg void OnKillFocus(CWnd* pNewWnd);
                afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
                afx_msg void OnNcDestroy();
                afx_msg void OnCloseup();
    //}}AFX_MSG

        DECLARE_MESSAGE_MAP()
        private:
                int                 m_iItem;
                int                 m_iSubItem;
                CStringList     m_lstItems;
                int                 m_nSel;
                BOOL            m_bESC;                 // ESC ۰¡ ´­·È´ÂÁö ³ªÅ¸³»±â À§ÇØ
};

CInPlaceList ÀÇ »ý¼ºÀÚ´Â ÀÎÀÚ·Î ³Ñ¾î¿Â °ªµéÀ» ÀúÀåÇϰí m_bESC¸¦ FALSE·Î ÃʱâÈ­ÇÕ´Ï´Ù. OnCreate()ÇÔ¼ö´Â µå·Ó´Ù¿î¸®½ºÆ® ÄÁÆ®·ÑÀ» »ý¼ºÇϰí Àû´çÇÑ °ªÀ¸·Î ÃʱâÈ­ÇÕ´Ï´Ù. PreTranslateMessage()ÇÔ¼ö´Â ¿¡µðÆ® ÄÁÆ®·Ñ¿¡ Àü´ÞµÇ´Â ESC¿Í ¿£ÅÍŰ È®ÀÎÀ» À§ÇØ ¿À¹ö¶óÀ̵åµË´Ï´Ù. ESC Ű¿Í ¿£ÅÍŰ´Â º¸Åë CDialog ³ª CFormView °´Ã¼¿¡ ÀÇÇØ Pre-Translate µË´Ï´Ù. ±×·¯¹Ç·Î ¿ì¸®´Â À̰͵鿡 ´ëÇØ Ưº°È÷ üũÇÏ¿© µå·Ó´Ù¿î ¸®½ºÆ® ÄÁÆ®·Ñ·Î ³Ñ±é´Ï´Ù.

OnKillFocus()ÇÔ¼ö´Â LVN_ENDLABELEDITÅëÁö¸¦ º¸³»°í ÄÞº¸¹Ú½ºÄÁÆ®·ÑÀ» ÆÄ±«ÇÕ´Ï´Ù.
ÅëÁö ¸Þ½ÃÁö´Â ¸®½ºÆ®ºä ÄÁÆ®·ÑÀÌ ¾Æ´Ñ ¸®½ºÆ®ºäÀÇ ºÎ¸ð¿¡°Ô º¸³»Áý´Ï´Ù. ÅëÁö¸¦ º¸³¾¶§ m_bESC ¸â¹ö º¯¼ö¸¦ °¡Áö
°í NULL ½ºÆ®¸µÀ» º¸³¾Áö¸¦ °áÁ¤ÇÕ´Ï´Ù.

OnNcDestroy() ÇÔ¼ö°¡ C++ °´Ã¼¸¦ ÆÄ±«Çϴµ¥ ÀûÀýÇÑ Àå¼ÒÀÔ´Ï´Ù.

OnChar() ÇÔ¼ö´Â ESC ³ª ¿£ÅͰ¡ ´­·ÈÀ»¶§ ¼±ÅÃÀ» ³¡³À´Ï´Ù. ÀÌ ÇÔ¼ö´Â ¸®½ºÆ®ºä¿¡Æ÷Ä¿½º¸¦ ÁÜÀ¸·Î½á ÄÞº¸¹Ú½º ÄÁÆ®·ÑÀÇ OnKillFocus() ÇÔ¼ö°¡ ºÒ·ÁÁöµµ·Ï ÇÕ´Ï´Ù.
OnChar() ÇÔ¼ö´Â ´Ù¸¥ ¹®ÀÚ¿¡ ´ëÇØ¼± º£À̽º Ŭ·¡½º ÇÔ¼ö°¡ ó¸®Çϵµ·Ï ÇÕ´Ï´Ù.

OnCloseup()ÇÔ¼ö´Â »ç¿ëÀÚ°¡ µå·Ó´Ù¿î ¸®½ºÆ®¿¡¼­ ¼±ÅÃÇßÀ»¶§ È£ÃâµË´Ï´Ù. ÀÌÇÔ¼ö´ÂºÎ¸ð¿¡¼­ ÀÔ·Â Æ÷Ä¿½º¸¦ ÁÜÀ¸·Î½á ¾ÆÀÌÅÛ ¼±ÅÃÀ» ³¡¸¶Ä¡°Ô ÇÕ´Ï´Ù.
 

// InPlaceList.cpp : implementation file

#include "stdafx.h"
#include "InPlaceList.h"

#ifdef _DEBUG
        #define new     DEBUG_NEW
        #undef          THIS_FILE
        static char     THIS_FILE[] = __FILE__;
#endif

// CInPlaceList

CInPlaceList::~CInPlaceList()   {       }

CInPlaceList::CInPlaceList(int iItem, int iSubItem, CStringList *plstItems, int nSel)
{
        m_iItem         = iItem;
        m_iSubItem      = iSubItem;
        m_lstItems.AddTail( plstItems );
        m_nSel          = nSel;
        m_bESC          = FALSE;
}

BEGIN_MESSAGE_MAP(CInPlaceList, CComboBox)
        //{{AFX_MSG_MAP(CInPlaceList)
        ON_WM_CREATE()
        ON_WM_KILLFOCUS()
        ON_WM_CHAR()
        ON_WM_NCDESTROY()
        ON_CONTROL_REFLECT(CBN_CLOSEUP, OnCloseup)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

// CInPlaceList message handlers

int CInPlaceList::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CComboBox::OnCreate(lpCreateStruct) == -1)  return -1;
        // Set the proper font
        CFont* font = GetParent()->GetFont();
        SetFont(font);

        for( POSITION pos = m_lstItems.GetHeadPosition(); pos != NULL; )        {
                AddString( (LPCTSTR) (m_lstItems.GetNext( pos )));    
        }
        SetCurSel( m_nSel );
        SetFocus();
        return 0;
}

BOOL CInPlaceList::PreTranslateMessage(MSG* pMsg)
{
        if( pMsg->message == WM_KEYDOWN )       {
        if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)      {
                        ::TranslateMessage(pMsg);
                        ::DispatchMessage(pMsg);
                        return TRUE;                // ´õÀÌ»ó ó¸®ÇÏÁö ¾Ê´Â´Ù.
                }
        }
        return CComboBox::PreTranslateMessage(pMsg);
}

void CInPlaceList::OnKillFocus(CWnd* pNewWnd)
{
        CComboBox::OnKillFocus(pNewWnd);
    
        CString str;
        GetWindowText(str);

        // ¸®½ºÆ®ºä ÄÁÆ®·ÑÀÇ ºÎ¸ð¿¡°Ô ÅëÁö º¸³»±â
        LV_DISPINFO     dispinfo;
        dispinfo.hdr.hwndFrom           = GetParent()->m_hWnd;
        dispinfo.hdr.idFrom             = GetDlgCtrlID();
        dispinfo.hdr.code                       = LVN_ENDLABELEDIT;
        dispinfo.item.mask              = LVIF_TEXT;
        dispinfo.item.iItem             = m_iItem;
        dispinfo.item.iSubItem          = m_iSubItem;
        dispinfo.item.pszText           = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
        dispinfo.item.cchTextMax        = str.GetLength();
        GetParent()->GetParent()->SendMessage( WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM)&dispinfo );
        DestroyWindow();
}

void CInPlaceList::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
        if( nChar == VK_ESCAPE || nChar == VK_RETURN)           {
                if( nChar == VK_ESCAPE )        m_bESC = TRUE;
                GetParent()->SetFocus();
                return;
        }
        CComboBox::OnChar(nChar, nRepCnt, nFlags);
}

void CInPlaceList::OnNcDestroy()
{
        CComboBox::OnNcDestroy();
        delete this;
}

void CInPlaceList::OnCloseup()
{
        GetParent()->SetFocus();
}