首页 > 代码库 > WinCE下带编辑与下拉功能的ListCtrl

WinCE下带编辑与下拉功能的ListCtrl

CListCtrl带编辑功能与下拉功能的本质即在列表中嵌入CEdit和CComboBox控件,其具体代码如下所示:
//InPlaceEdit.h
#if !defined(AFX_INPLACEEDIT_H__175AEDFF_731E_4721_8399_DE406A465861__INCLUDED_)
#define AFX_INPLACEEDIT_H__175AEDFF_731E_4721_8399_DE406A465861__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CInPlaceEdit : public CEdit
{

public:
 
// Implementation
 
 // Returns the instance of the class
 static CInPlaceEdit* GetInstance();

 // Deletes the instance of the class
 static void DeleteInstance();

 // Creates the Windows edit control and attaches it to the object
 // Shows the edit ctrl
 BOOL ShowEditCtrl(DWORD dwStyle, const RECT& rCellRect, CWnd* pParentWnd,
       UINT uiResourceID, int iRowIndex, int iColumnIndex,
       CString& strValidChars, CString& rstrCurSelection);

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CInPlaceEdit)
 public:
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 //}}AFX_VIRTUAL


// Attributes
 // afx_msg void OnPaste(WPARAM wParam, LPARAM lParam);

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

 DECLARE_MESSAGE_MAP()

private:

// Implementation

 // Constructor
 CInPlaceEdit();

 // Hide the copy constructor and operator =
 CInPlaceEdit (CInPlaceEdit&) {}

 operator = (CInPlaceEdit) {}
 
 // Destructor
 virtual ~CInPlaceEdit();

// Attributes

 // Index of the item in the list control
 int m_iRowIndex;

 // Index of the subitem in the list control
 int m_iColumnIndex;

 // To indicate whether ESC key was pressed
 BOOL m_bESC;
 
 // Valid characters
 CString m_strValidChars;

 // Singleton instance
 static CInPlaceEdit* m_pInPlaceEdit;

 // Previous string value in the edit control
 CString m_strWindowText;
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_INPLACEEDIT_H__175AEDFF_731E_4721_8399_DE406A465861__INCLUDED_)

//InPlaceEdit.cpp
#include "stdafx.h"
#include "InPlaceEdit.h"

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

#define CTRL_C 0x3
#define CTRL_V 0x16
#define CTRL_X 0x18

/////////////////////////////////////////////////////////////////////////////
// CInPlaceEdit

CInPlaceEdit* CInPlaceEdit::m_pInPlaceEdit = NULL; 

CInPlaceEdit::CInPlaceEdit()
{
 m_iRowIndex= -1;
 m_iColumnIndex = -1;
 m_bESC = FALSE;
 m_strValidChars.Empty();
}

CInPlaceEdit::~CInPlaceEdit()
{
}

BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
 //{{AFX_MSG_MAP(CInPlaceEdit)
 ON_WM_KILLFOCUS()
 ON_WM_CHAR() 
 ON_WM_CREATE()
 //}}AFX_MSG_MAP
// ON_MESSAGE(WM_PASTE, OnPaste)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInPlaceEdit message handlers
/*
void CInPlaceEdit::OnPaste(WPARAM , LPARAM )
{
 if (m_strValidChars.IsEmpty())
 {
  return; 
 }

    CString strFromClipboard;

 // get the text from clipboard
 if(OpenClipboard()) {
  HANDLE l_hData = http://www.mamicode.com/GetClipboardData(CF_TEXT);
  if(NULL == l_hData) {
   return;
  }
  
  char *l_pBuffer = (char*)GlobalLock(l_hData);
  if(NULL != l_pBuffer) {
   strFromClipboard = l_pBuffer;
  }

  GlobalUnlock(l_hData);
  CloseClipboard();
 }

 // Validate the characters before pasting
 for(int iCounter_ = 0; iCounter_ < strFromClipboard.GetLength(); iCounter_++)
 {
  if (-1 == m_strValidChars.Find(strFromClipboard.GetAt(iCounter_)))
  {
   return;
  }
 }
  
 //let the individual control handle other processing
 CEdit::Default(); 
}
*/

void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
{
 CEdit::OnKillFocus(pNewWnd);
 
 // TODO: Add your message handler code here

 // Get the text in the edit ctrl
 CString strEdit;
 GetWindowText(strEdit);

// if(strEdit.GetLength() == 1)
//  strEdit = _T("0") + strEdit;

 // Send Notification to parent of edit ctrl
 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_iRowIndex;
 dispinfo.item.iSubItem = m_iColumnIndex;
 dispinfo.item.pszText = m_bESC ? LPTSTR((LPCTSTR)m_strWindowText) : LPTSTR((LPCTSTR)strEdit);
 dispinfo.item.cchTextMax = m_bESC ? m_strWindowText.GetLength() : strEdit.GetLength();
 
 GetParent()->SendMessage(WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM)&dispinfo);

 PostMessage(WM_CLOSE);
}

void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 // TODO: Add your message handler code here and/or call default

  if ((m_strValidChars.IsEmpty()) || ((-1 != m_strValidChars.Find(static_cast<TCHAR> (nChar))) ||
  (nChar == VK_BACK) || (nChar == CTRL_C) || (nChar == CTRL_V) || (nChar == CTRL_X)))
 {
  CEdit::OnChar(nChar, nRepCnt, nFlags);
 }
 else
 {
  MessageBeep(MB_ICONEXCLAMATION);
  return;
 }
}

BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
{
 // TODO: Add your specialized code here and/or call the base class
 if (WM_KEYDOWN == pMsg->message && (VK_ESCAPE == pMsg->wParam || VK_RETURN == pMsg->wParam))
 {
  if (VK_ESCAPE == pMsg->wParam)
  {
   m_bESC = TRUE;
  }

  GetParent()->SetFocus();
  return TRUE;
 }

 return CEdit::PreTranslateMessage(pMsg);
}

int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CEdit::OnCreate(lpCreateStruct) == -1)
  return -1;
 
 // TODO: Add your specialized creation code here
 // Set the proper font
 CFont* pFont = GetParent()->GetFont();
 SetFont(pFont);

 ShowWindow(SW_SHOW);
 SetWindowText(m_strWindowText);
 SetSel(0, -1);
 SetFocus();
 
  
 return 0;
}

CInPlaceEdit* CInPlaceEdit::GetInstance()
{
 if(m_pInPlaceEdit == NULL)
 {
  m_pInPlaceEdit = new CInPlaceEdit;
 }
 return m_pInPlaceEdit;
}

void CInPlaceEdit::DeleteInstance()
{
 delete m_pInPlaceEdit;
 m_pInPlaceEdit = NULL;
}

BOOL CInPlaceEdit::ShowEditCtrl(DWORD dwStyle, const RECT &rCellRect, CWnd* pParentWnd,
        UINT uiResourceID, int iRowIndex, int iColumnIndex,
        CString& strValidChars, CString& rstrCurSelection)
{
 m_iRowIndex = iRowIndex;
 m_iColumnIndex = iColumnIndex;
 m_strValidChars = strValidChars;
 m_strWindowText = rstrCurSelection;
 m_bESC = FALSE;

 if (NULL == m_pInPlaceEdit->m_hWnd)
 {
  return m_pInPlaceEdit->Create(dwStyle, rCellRect, pParentWnd, uiResourceID);
 } 

 return TRUE;
}

//InPlaceCombo.h
#if !defined(AFX_INPLACECOMBO_H__2E04D8D9_827F_4FBD_9E87_30AF8C31639D__INCLUDED_)
#define AFX_INPLACECOMBO_H__2E04D8D9_827F_4FBD_9E87_30AF8C31639D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CInPlaceCombo : public CComboBox
{
public:
  
// Implementation
 
 // Returns the instance of the class
 static CInPlaceCombo* GetInstance();

 // Deletes the instance of the class
 static void DeleteInstance();

 // Creates the Windows combo control and attaches it to the object, if needed and shows the combo ctrl
 BOOL ShowComboCtrl(DWORD dwStyle, const CRect& rCellRect, CWnd* pParentWnd, UINT uiResourceID,
        int iRowIndex, int iColumnIndex, CStringList* pDropDownList, CString strCurSelecetion = "", int iCurSel = -1);

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CInPlaceCombo)
 public:
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 //}}AFX_VIRTUAL

protected:

 // Generated message map functions
 //{{AFX_MSG(CInPlaceCombo)
 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 OnCloseup();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()

private:

// Implementation
 // Constructor
 CInPlaceCombo();

 // Hide the copy constructor and operator =
 CInPlaceCombo (CInPlaceCombo&) {}

 operator = (CInPlaceCombo) {}

 // Destructor
 virtual ~CInPlaceCombo();

// Attributes

 // Index of the item in the list control
 int m_iRowIndex;

 // Index of the subitem in the list control
 int m_iColumnIndex;

 // To indicate whether ESC key was pressed
 BOOL m_bESC;
 
 // Singleton instance
 static CInPlaceCombo* m_pInPlaceCombo;

 // Previous selected string value in the combo control
 CString m_strWindowText;

 // List of items to be shown in the drop down
 CStringList m_DropDownList;
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_INPLACECOMBO_H__2E04D8D9_827F_4FBD_9E87_30AF8C31639D__INCLUDED_)

//InPlaceCombo.cpp
#include "stdafx.h"
#include "InPlaceCombo.h"

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

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCombo

CInPlaceCombo* CInPlaceCombo::m_pInPlaceCombo = NULL;

CInPlaceCombo::CInPlaceCombo()
{
 m_iRowIndex = -1;
 m_iColumnIndex = -1;
 m_bESC = FALSE;
}

CInPlaceCombo::~CInPlaceCombo()
{
}

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

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCombo message handlers

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

 ResetContent();
 for (POSITION Pos_ = m_DropDownList.GetHeadPosition(); Pos_ != NULL;)
 {
  AddString((LPCTSTR) (m_DropDownList.GetNext(Pos_)));
 }

 return 0;
}

BOOL CInPlaceCombo::PreTranslateMessage(MSG* pMsg)
{
 // If the message if for "Enter" or "Esc"
 // Do not process
 if (pMsg->message == WM_KEYDOWN)
 {
  if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
  {
   ::TranslateMessage(pMsg);
   ::DispatchMessage(pMsg);
   // DO NOT process further
   return TRUE;    
  }
 }
 
 return CComboBox::PreTranslateMessage(pMsg);
}

void CInPlaceCombo::OnKillFocus(CWnd* pNewWnd)
{
 CComboBox::OnKillFocus(pNewWnd);
 
 // Get the current selection text
 CString str;
 GetWindowText(str);

 // Send Notification to parent of ListView ctrl
 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_iRowIndex;
 dispinfo.item.iSubItem = m_iColumnIndex;
 dispinfo.item.pszText = m_bESC ? LPTSTR((LPCTSTR)m_strWindowText) : LPTSTR((LPCTSTR)str);
 dispinfo.item.cchTextMax = m_bESC ? m_strWindowText.GetLength() : str.GetLength();
 
 GetParent()->SendMessage(WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM)&dispinfo);

 // Close the control
 PostMessage(WM_CLOSE);
}

void CInPlaceCombo::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 // If the key is "Esc" set focus back to the list control
 if (nChar == VK_ESCAPE || nChar == VK_RETURN)
 {
  if (nChar == VK_ESCAPE)
  {
   m_bESC = TRUE;
  }

  GetParent()->SetFocus();
  return;
 }
 
 CComboBox::OnChar(nChar, nRepCnt, nFlags);
}

void CInPlaceCombo::OnCloseup()
{
 // Set the focus to the parent list control
 GetParent()->SetFocus();
}

CInPlaceCombo* CInPlaceCombo::GetInstance()
{
 if(m_pInPlaceCombo == NULL)
 {
  m_pInPlaceCombo = new CInPlaceCombo;
 }
 return m_pInPlaceCombo;
}

void CInPlaceCombo::DeleteInstance()
{
 delete m_pInPlaceCombo;
 m_pInPlaceCombo = NULL;
}

BOOL CInPlaceCombo::ShowComboCtrl(DWORD dwStyle, const CRect &rCellRect, CWnd* pParentWnd, UINT uiResourceID,
          int iRowIndex, int iColumnIndex, CStringList* pDropDownList,
          CString strCurSelecetion /*= ""*/, int iCurSel /*= -1*/)
{

 m_iRowIndex = iRowIndex;
 m_iColumnIndex = iColumnIndex;
 m_bESC = FALSE;
 
 m_DropDownList.RemoveAll();
 m_DropDownList.AddTail(pDropDownList);

 BOOL bRetVal = TRUE;

 if (-1 != iCurSel)
 {
  GetLBText(iCurSel, m_strWindowText);
 }
 else if (!strCurSelecetion.IsEmpty())
 {
  m_strWindowText = strCurSelecetion;
 }
 
 if (NULL == m_pInPlaceCombo->m_hWnd)
 {
  bRetVal = m_pInPlaceCombo->Create(dwStyle, rCellRect, pParentWnd, uiResourceID);
 }

 SetCurSel(iCurSel);

 return bRetVal;
}

//MyComboListCtrl.h
#if !defined(AFX_MYCOMBOLISTCTRL_H__9089600F_374F_4BFC_9482_DEAC0E7133E8__INCLUDED_)
#define AFX_MYCOMBOLISTCTRL_H__9089600F_374F_4BFC_9482_DEAC0E7133E8__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

//the max listCtrl columns
#define MAX_LISTCTRL_COLUMNS 100

#include <afxtempl.h>
#include <afxcmn.h>

class CInPlaceCombo;
class CInPlaceEdit;

// User define message
// This message is posted to the parent
// The message can be handled to make the necessary validations, if any
#define WM_VALIDATE  WM_USER + 0x7FFD

// User define message
// This message is posted to the parent
// The message should be handled to spcify the items to the added to the combo
#define WM_SET_ITEMS WM_USER + 0x7FFC

class CMyComboListCtrl : public CListCtrl
{
public:
 
// Implementation
 typedef enum {MODE_READONLY,MODE_DIGITAL_EDIT,MODE_TEXT_EDIT,MODE_COMBO} COMBOLISTCTRL_COLUMN_MODE;

 // Constructor
 CMyComboListCtrl();

 // Destructor
 virtual ~CMyComboListCtrl();

 // Sets/Resets the column which support the in place combo box
 void SetComboColumns(int iColumnIndex, bool bSet = true);
 
 // Sets/Resets the column which support the in place edit control
 void SetReadOnlyColumns(int iColumnIndex, bool bSet = true);

 // Sets the valid characters for the edit ctrl
 void SetValidEditCtrlCharacters(CString& rstrValidCharacters);

 // Sets the vertical scroll
 void EnableVScroll(bool bEnable = true);

 // Sets the horizontal scroll
 void EnableHScroll(bool bEnable = true);

 //insert column
 int CMyComboListCtrl::InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat = LVCFMT_LEFT,int nWidth = -1,int nSubItem = -1);

 //Get column counts
 int GetColumnCounts();

 //delete all column
 void DeleteAllColumn();

 //set column Valid char string
 void SetColumnValidEditCtrlCharacters(CString &rstrValidCharacters,int column = -1);

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CMyComboListCtrl)
 //}}AFX_VIRTUAL

protected:

// Methods
 // Generated message map functions
 //{{AFX_MSG(CMyComboListCtrl)
 afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
 afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 afx_msg void OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
 afx_msg void OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
 //}}AFX_MSG

 DECLARE_MESSAGE_MAP()

private:
   
// Implementation

 // Returns the row & column index of the column on which mouse click event has occured
 bool HitTestEx(CPoint& rHitPoint, int* pRowIndex, int* pColumnIndex) const;

 // Creates and displays the in place combo box
 CInPlaceCombo* ShowInPlaceList(int iRowIndex, int iColumnIndex, CStringList& rComboItemsList,
           CString strCurSelecetion = "", int iSel = -1);

 // Creates and displays the in place edit control
 CInPlaceEdit* ShowInPlaceEdit(int iRowIndex, int iColumnIndex, CString& rstrCurSelection);

 // Calculates the cell rect
 void CalculateCellRect(int iColumnIndex, int iRowIndex, CRect& robCellRect);

 // Checks whether column supports in place combo box
 bool IsCombo(int iColumnIndex);

 // Checks whether column is read only
 bool IsReadOnly(int iColumnIndex);

 // Scrolls the list ctrl to bring the in place ctrl to the view
 void ScrollToView(int iColumnIndex, /*int iOffSet, */CRect& obCellRect);

// Attributes
 
 // List of columns that support the in place combo box
 CList<int, int> m_ComboSupportColumnsList;

 // List of columns that are read only
 CList<int, int> m_ReadOnlyColumnsList;

 // Valid characters
 CString m_strValidEditCtrlChars;

 // The window style of the in place edit ctrl
 DWORD m_dwEditCtrlStyle;

 // The window style of the in place combo ctrl
 DWORD m_dwDropDownCtrlStyle;

 //columnCounts
 int m_iColumnCounts;

 //column types
 COMBOLISTCTRL_COLUMN_MODE m_modeColumn[MAX_LISTCTRL_COLUMNS];

 //column
 CString m_strValidChars[MAX_LISTCTRL_COLUMNS];
 //int m_
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MYCOMBOLISTCTRL_H__9089600F_374F_4BFC_9482_DEAC0E7133E8__INCLUDED_)


//MyComboListCtrl.cpp
#include "stdafx.h"
#include "MyComboListCtrl.h"
#include "InPlaceCombo.h"
#include "InPlaceEdit.h"

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

//#defines
#define FIRST_COLUMN    0
#define MIN_COLUMN_WIDTH   10
#define MAX_DROP_DOWN_ITEM_COUNT 10

/////////////////////////////////////////////////////////////////////////////
// CMyComboListCtrl

CMyComboListCtrl::CMyComboListCtrl()
{
 m_iColumnCounts = 0;
 m_ComboSupportColumnsList.RemoveAll();
 m_ReadOnlyColumnsList.RemoveAll();
 m_strValidEditCtrlChars.Empty();
 m_dwEditCtrlStyle = ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_NOHIDESEL;
 m_dwDropDownCtrlStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
       CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL;
}

CMyComboListCtrl::~CMyComboListCtrl()
{
 CInPlaceCombo::DeleteInstance();
 CInPlaceEdit::DeleteInstance(); 
}


BEGIN_MESSAGE_MAP(CMyComboListCtrl, CListCtrl)
 //{{AFX_MSG_MAP(CMyComboListCtrl)
 ON_WM_HSCROLL()
 ON_WM_VSCROLL()
 ON_WM_LBUTTONDOWN()
 ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndLabelEdit)
 ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginLabelEdit)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyComboListCtrl message handlers

CInPlaceCombo* CMyComboListCtrl::ShowInPlaceList(int iRowIndex, int iColumnIndex, CStringList& rComboItemsList,
              CString strCurSelecetion /*= ""*/, int iSel /*= -1*/)
{
 // The returned obPointer should not be saved
 
 // Make sure that the item is visible
 if (!EnsureVisible(iRowIndex, TRUE))
 {
  return NULL;
 }

 // Make sure that iColumnIndex is valid
 CHeaderCtrl* pHeader = static_cast<CHeaderCtrl*> (GetDlgItem(FIRST_COLUMN));

 int iColumnCount = pHeader->GetItemCount();

 if (iColumnIndex >= iColumnCount || GetColumnWidth(iColumnIndex) < MIN_COLUMN_WIDTH)
 {
  return NULL;
 }

 // Calculate the rectangle specifications for the combo box
 CRect obCellRect(0, 0, 0, 0);
 CalculateCellRect(iColumnIndex, iRowIndex, obCellRect);

 int iHeight = obCellRect.Height(); 
 int iCount = (int )rComboItemsList.GetCount();

 iCount = (iCount < MAX_DROP_DOWN_ITEM_COUNT) ?
  iCount + MAX_DROP_DOWN_ITEM_COUNT : (MAX_DROP_DOWN_ITEM_COUNT + 1);

 obCellRect.bottom += iHeight * iCount;

 // Create the in place combobox
 CInPlaceCombo* pInPlaceCombo = CInPlaceCombo::GetInstance();
 pInPlaceCombo->ShowComboCtrl(m_dwDropDownCtrlStyle, obCellRect, this, 0, iRowIndex, iColumnIndex, &rComboItemsList,
         strCurSelecetion, iSel);
 
 return pInPlaceCombo;
}

CInPlaceEdit* CMyComboListCtrl::ShowInPlaceEdit(int iRowIndex, int iColumnIndex, CString& rstrCurSelection)
{
 // Create an in-place edit control
 CInPlaceEdit* pInPlaceEdit = CInPlaceEdit::GetInstance();
  
 CRect obCellRect(0, 0, 0, 0);
 CalculateCellRect(iColumnIndex, iRowIndex, obCellRect);
   
 pInPlaceEdit->ShowEditCtrl(m_dwEditCtrlStyle, obCellRect, this, 0,
          iRowIndex, iColumnIndex,
          m_strValidChars[iColumnIndex], rstrCurSelection);

 return pInPlaceEdit;
}

void CMyComboListCtrl::OnHScroll(UINT iSBCode, UINT iPos, CScrollBar* pScrollBar)
{
 // TODO: Add your message handler code here and/or call default

 if (GetFocus() != this)
 {
  SetFocus();
 }

 CListCtrl::OnHScroll(iSBCode, iPos, pScrollBar);
}

void CMyComboListCtrl::OnVScroll(UINT iSBCode, UINT iPos, CScrollBar* pScrollBar)
{
 // TODO: Add your message handler code here and/or call default

 if (GetFocus() != this)
 {
  SetFocus();
 }

 CListCtrl::OnVScroll(iSBCode, iPos, pScrollBar);
}

void CMyComboListCtrl::OnLButtonDown(UINT iFlags, CPoint obPoint)
{
 // TODO: Add your message handler code here and/or call default

 int iColumnIndex = -1;
 int iRowIndex = -1;

 // Get the current column and row
 if (!HitTestEx(obPoint, &iRowIndex, &iColumnIndex))
 {
  return;
 }

 CListCtrl::OnLButtonDown(iFlags, obPoint);
 
 // If column is not read only then
 // If the SHIFT or CTRL key is down call the base class
 // Check the high bit of GetKeyState to determine whether SHIFT or CTRL key is down
 if ((GetKeyState(VK_SHIFT) & 0x80) || (GetKeyState(VK_CONTROL) & 0x80))
 {
  return;
 }

 // Get the current selection before creating the in place combo box
 CString strCurSelection = GetItemText(iRowIndex, iColumnIndex);
 
 if (-1 != iRowIndex)
 {
  UINT flag = LVIS_FOCUSED;
  
  if ((GetItemState(iRowIndex, flag ) & flag) == flag)
  {
   // Add check for LVS_EDITLABELS
   if (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS)
   {
    // If combo box is supported
    // Create and show the in place combo box
    if (IsCombo(iColumnIndex))
    {
     CStringList obComboItemsList;
          
     GetParent()->SendMessage(WM_SET_ITEMS, (WPARAM)iColumnIndex, (LPARAM)&obComboItemsList); 
     
     CInPlaceCombo* pInPlaceComboBox = ShowInPlaceList(iRowIndex, iColumnIndex, obComboItemsList, strCurSelection);
     ASSERT(pInPlaceComboBox);
     
     // Set the selection to previous selection
     pInPlaceComboBox->SelectString(-1, strCurSelection);
    }
    // If combo box is not read only
    // Create and show the in place edit control
    else if (!IsReadOnly(iColumnIndex))
    {
     CInPlaceEdit* pInPlaceEdit = ShowInPlaceEdit(iRowIndex, iColumnIndex, strCurSelection);
    }
   }
  }
 } 
}

bool CMyComboListCtrl::HitTestEx(CPoint &obPoint, int* pRowIndex, int* pColumnIndex) const
{
 if (!pRowIndex || !pColumnIndex)
 {
  return false;
 }

 // Get the row index
 *pRowIndex = HitTest(obPoint, NULL);

 if (pColumnIndex)
 {
  *pColumnIndex = 0;
 }

 // Make sure that the ListView is in LVS_REPORT
 if ((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)
 {
  return false;
 }

 // Get the number of columns
 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);

 int iColumnCount = pHeader->GetItemCount();

 // Get bounding rect of item and check whether obPoint falls in it.
 CRect obCellRect;
 GetItemRect(*pRowIndex, &obCellRect, LVIR_BOUNDS);
 
 if (obCellRect.PtInRect(obPoint))
 {
  // Now find the column
  for (*pColumnIndex = 0; *pColumnIndex < iColumnCount; (*pColumnIndex)++)
  {
   int iColWidth = GetColumnWidth(*pColumnIndex);
   
   if (obPoint.x >= obCellRect.left && obPoint.x <= (obCellRect.left + iColWidth))
   {
    return true;
   }
   obCellRect.left += iColWidth;
  }
 }
 return false;
}

void CMyComboListCtrl::SetComboColumns(int iColumnIndex, bool bSet /*= true*/)
{
 // If the Column Index is not present && Set flag is false
 // Then do nothing
 // If the Column Index is present && Set flag is true
 // Then do nothing
 POSITION Pos = m_ComboSupportColumnsList.Find(iColumnIndex);

 // If the Column Index is not present && Set flag is true
 // Then Add to list
 if ((NULL == Pos) && bSet)
 {
  m_ComboSupportColumnsList.AddTail(iColumnIndex);
 }

 // If the Column Index is present && Set flag is false
 // Then Remove from list
 if ((NULL != Pos) && !bSet)
 {
  m_ComboSupportColumnsList.RemoveAt(Pos);
 }
}

void CMyComboListCtrl::SetReadOnlyColumns(int iColumnIndex, bool bSet /*= true*/)
{
 // If the Column Index is not present && Set flag is false
 // Then do nothing
 // If the Column Index is present && Set flag is true
 // Then do nothing
 POSITION Pos = m_ReadOnlyColumnsList.Find(iColumnIndex);

 // If the Column Index is not present && Set flag is true
 // Then Add to list
 if ((NULL == Pos) && bSet)
 {
  m_ReadOnlyColumnsList.AddTail(iColumnIndex);
 }

 // If the Column Index is present && Set flag is false
 // Then Remove from list
 if ((NULL != Pos) && !bSet)
 {
  m_ReadOnlyColumnsList.RemoveAt(Pos);
 }
}

bool CMyComboListCtrl::IsReadOnly(int iColumnIndex)
{
 if (m_ReadOnlyColumnsList.Find(iColumnIndex))
 {
  return true;
 }
 
 return false;
}

bool CMyComboListCtrl::IsCombo(int iColumnIndex)
{
 if (m_ComboSupportColumnsList.Find(iColumnIndex))
 {
  return true;
 }

 return false;
}

void CMyComboListCtrl::CalculateCellRect(int iColumnIndex, int iRowIndex, CRect& robCellRect)
{
 GetItemRect(iRowIndex, &robCellRect, LVIR_BOUNDS);
 
 CRect rcClient;
 GetClientRect(&rcClient);

 if (robCellRect.right > rcClient.right)
 {
  robCellRect.right = rcClient.right;
 }

 ScrollToView(iColumnIndex, robCellRect);
}

void CMyComboListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
 // TODO: Add your control notification handler code here
 
 // Update the item text with the new text
 SetItemText(pDispInfo->item.iItem, pDispInfo->item.iSubItem, pDispInfo->item.pszText);

 GetParent()->SendMessage(WM_VALIDATE, GetDlgCtrlID(), (LPARAM)pDispInfo);
 
 *pResult = 0;
}

void CMyComboListCtrl::SetValidEditCtrlCharacters(CString &rstrValidCharacters)
{
 m_strValidEditCtrlChars = rstrValidCharacters;
}

void CMyComboListCtrl::SetColumnValidEditCtrlCharacters(CString &rstrValidCharacters,int column)
{
 if(column>MAX_LISTCTRL_COLUMNS-1)
  return;
 if(column == -1)
 {
  for(int i=0;i<MAX_LISTCTRL_COLUMNS;i++)
  {
   m_strValidChars[i] = rstrValidCharacters;
  }
 }
 else
  m_strValidChars[column] = rstrValidCharacters;
}

void CMyComboListCtrl::EnableHScroll(bool bEnable /*= true*/)
{
 if (bEnable)
 {
  m_dwDropDownCtrlStyle |= WS_HSCROLL;
 }
 else
 {
  m_dwDropDownCtrlStyle &= ~WS_HSCROLL;
 } 
}

void CMyComboListCtrl::EnableVScroll(bool bEnable /*= true*/)
{
 if (bEnable)
 {
  m_dwDropDownCtrlStyle |= WS_VSCROLL;
 }
 else
 {
  m_dwDropDownCtrlStyle &= ~WS_VSCROLL;
 }
}

void CMyComboListCtrl::ScrollToView(int iColumnIndex, /*int iOffSet, */CRect& robCellRect)
{
 // Now scroll if we need to expose the column
 CRect rcClient;
 GetClientRect(&rcClient);

 int iColumnWidth = GetColumnWidth(iColumnIndex);

 // Get the column iOffset
 int iOffSet = 0;
 for (int iIndex_ = 0; iIndex_ < iColumnIndex; iIndex_++)
 {
  iOffSet += GetColumnWidth(iIndex_);
 }

 // If x1 of cell rect is < x1 of ctrl rect or
 // If x1 of cell rect is > x1 of ctrl rect or **Should not ideally happen**
 // If the width of the cell extends beyond x2 of ctrl rect then
 // Scroll

 CSize obScrollSize(0, 0);

 if (((iOffSet + robCellRect.left) < rcClient.left) ||
  ((iOffSet + robCellRect.left) > rcClient.right))
 {
  obScrollSize.cx = iOffSet + robCellRect.left;
 }
 else if ((iOffSet + robCellRect.left + iColumnWidth) > rcClient.right)
 {
  obScrollSize.cx = iOffSet + robCellRect.left + iColumnWidth - rcClient.right;
 }

 Scroll(obScrollSize);
 robCellRect.left -= obScrollSize.cx;
 
 // Set the width to the column width
 robCellRect.left += iOffSet;
 robCellRect.right = robCellRect.left + iColumnWidth;
}

void CMyComboListCtrl::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
 // TODO: Add your control notification handler code here
 if (IsReadOnly(pDispInfo->item.iSubItem))
 {
  *pResult = 1;
  return;
 }

 *pResult = 0;
}

int CMyComboListCtrl::InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat ,int nWidth,int nSubItem)
{
 m_iColumnCounts++;
 return CListCtrl::InsertColumn( nCol, lpszColumnHeading, nFormat, nWidth, nSubItem);
}

int CMyComboListCtrl::GetColumnCounts()
{
 return m_iColumnCounts;
}

void CMyComboListCtrl::DeleteAllColumn()
{
 for(int i=0;i<m_iColumnCounts;i++)
 {
  DeleteColumn(0);
 }
}

//应用
LRESULT CRTUProtocolIndexInfoBaseDlg::PopulateComboList(WPARAM wParam, LPARAM lParam)
{
 // Get the Combobox window pointer
 CComboBox* pInPlaceCombo = static_cast<CComboBox *>(GetFocus());

 // Get the inplace combbox top left
 CRect obWindowRect;

 pInPlaceCombo->GetWindowRect(&obWindowRect);
 
 CPoint obInPlaceComboTopLeft(obWindowRect.TopLeft());
 
 // Get the active list
 // Get the control window rect
 // If the inplace combobox top left is in the rect then
 // The control is the active control
 CWnd *pFocusWnd = GetFocus();
 pFocusWnd->GetWindowRect(&obWindowRect); 
 
 int iColIndex = (int)wParam;
 
 CStringList* pComboList = reinterpret_cast<CStringList *>(lParam);
 pComboList->RemoveAll();
 
 if(obWindowRect.PtInRect(obInPlaceComboTopLeft))
 {    
  if((iColIndex == 1) || (iColIndex == 2))
  {
   pComboList->AddTail(_T("是"));
   pComboList->AddTail(_T("否")); 
  }   
 }
 return true;
}

//初始化列
 CFont font;
 VERIFY(font.CreateFont(
    18,                        // nHeight
    0,                         // nWidth
    0,                         // nEscapement
    0,                         // nOrientation
    FW_NORMAL,                 // nWeight
    FALSE,                     // bItalic
    FALSE,                     // bUnderline
    0,                         // cStrikeOut
    ANSI_CHARSET,              // nCharSet
    OUT_DEFAULT_PRECIS,        // nOutPrecision
    CLIP_DEFAULT_PRECIS,       // nClipPrecision
    DEFAULT_QUALITY,           // nQuality
    DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
    _T("宋体")));
 m_CtrlListBaseInfo.SetFont(&font);
 m_CtrlListBaseInfo.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

 m_CtrlListBaseInfo.InsertColumn(0, _T("序号"), LVCFMT_CENTER, 40);
 m_CtrlListBaseInfo.InsertColumn(1, _T("有效标志"), LVCFMT_CENTER, 60);

 m_CtrlListBaseInfo.SetReadOnlyColumns(0);  //read only
 m_CtrlListBaseInfo.SetReadOnlyColumns(1);  //read only
 m_CtrlListBaseInfo.SetComboColumns(1, TRUE);
 m_CtrlListBaseInfo.EnableVScroll();

m_CtrlListBaseInfo.InsertColumn(2, _T("功能码"), LVCFMT_CENTER, 80);
 
 CString strValidChars(_T("0123456789ABCDEFabcdef"));
 m_CtrlListBaseInfo.SetColumnValidEditCtrlCharacters(strValidChars, 2);//HEX only edit