和C++中一样,WinCE下可编辑的ListCtrl控件也是将Edit控件置于列表框中以达到可编辑的功能,在此我们需要重载CListCtrl和CEdit控件以完成其功能,具体代码如下:
//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 = 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);
// 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;
}
//ComboListCtrl.h
#if !defined(AFX_COMBOLISTCTRL_H__9089600F_374F_4BFC_9482_DEAC0E7133E8__INCLUDED_)
#define AFX_COMBOLISTCTRL_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>
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 CComboListCtrl : public CListCtrl
{
public:
// Implementation
typedef enum {MODE_READONLY,MODE_DIGITAL_EDIT,MODE_TEXT_EDIT,MODE_COMBO} COMBOLISTCTRL_COLUMN_MODE;
// Constructor
CComboListCtrl();
// Destructor
virtual ~CComboListCtrl();
// Sets/Resets the column which support the in place combo box
// 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
// Sets the horizontal scroll
//insert column
int CComboListCtrl::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(CComboListCtrl)
//}}AFX_VIRTUAL
protected:
// Methods
// Generated message map functions
//{{AFX_MSG(CComboListCtrl)
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
// 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
// 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 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;
//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_COMBOLISTCTRL_H__9089600F_374F_4BFC_9482_DEAC0E7133E8__INCLUDED_)
//ComboListCtrl.cpp
#include "stdafx.h"
#include "ComboListCtrl.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
/////////////////////////////////////////////////////////////////////////////
// CComboListCtrl
CComboListCtrl::CComboListCtrl()
{
m_iColumnCounts = 0;
m_ReadOnlyColumnsList.RemoveAll();
m_strValidEditCtrlChars.Empty();
m_dwEditCtrlStyle = ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_NOHIDESEL;
}
CComboListCtrl::~CComboListCtrl()
{
CInPlaceEdit::DeleteInstance();
}
BEGIN_MESSAGE_MAP(CComboListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CComboListCtrl)
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()
/////////////////////////////////////////////////////////////////////////////
// CComboListCtrl message handlers
CInPlaceEdit* CComboListCtrl::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 CComboListCtrl::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 CComboListCtrl::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 CComboListCtrl::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 (!IsReadOnly(iColumnIndex))
{
CInPlaceEdit* pInPlaceEdit = ShowInPlaceEdit(iRowIndex, iColumnIndex, strCurSelection);
}
}
}
}
}
bool CComboListCtrl::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 CComboListCtrl::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 CComboListCtrl::IsReadOnly(int iColumnIndex)
{
if (m_ReadOnlyColumnsList.Find(iColumnIndex))
{
return true;
}
return false;
}
void CComboListCtrl::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 CComboListCtrl::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 CComboListCtrl::SetValidEditCtrlCharacters(CString &rstrValidCharacters)
{
m_strValidEditCtrlChars = rstrValidCharacters;
}
void CComboListCtrl::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 CComboListCtrl::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 CComboListCtrl::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 CComboListCtrl::InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat ,int nWidth,int nSubItem)
{
m_iColumnCounts++;
return CListCtrl::InsertColumn( nCol, lpszColumnHeading, nFormat, nWidth, nSubItem);
}
int CComboListCtrl::GetColumnCounts()
{
return m_iColumnCounts;
}
void CComboListCtrl::DeleteAllColumn()
{
for(int i=0;i<m_iColumnCounts;i++)
{
DeleteColumn(0);
}
}
//应用
CComboListCtrl m_CtrlList;
m_CtrlList.InsertColumn(0, _T("编号"), LVCFMT_CENTER, 50);
m_CtrlList.InsertColumn(1, _T("姓名"), LVCFMT_CENTER, 80);
m_CtrlList.InsertColumn(2, _T("学号"), LVCFMT_CENTER, 80);
m_CtrlList.InsertColumn(3, _T("性别"), LVCFMT_CENTER, 80);
CString strValidChars;//
m_CtrlList.SetReadOnlyColumns(0);//read only
strValidChars = _T("");
m_CtrlList.SetColumnValidEditCtrlCharacters(strValidChars,1);//none control edit
strValidChars = _T("0123456789.");
m_CtrlList.SetColumnValidEditCtrlCharacters(strValidChars,2);//digital only edit
m_CtrlList.SetReadOnlyColumns(3);//read only
CFont font;
VERIFY(font.CreateFont(
20, // 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_CtrlList.SetFont(&font);
m_CtrlList.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
CString str;
for(int i=0;i<30;i++)
{
str.Format(_T("%d"), i+1);
m_CtrlList.InsertItem(i, str);
m_CtrlList.SetItemText(i, 1, _T("张三"));
m_CtrlList.SetItemText(i, 2, _T("1234"));
m_CtrlList.SetItemText(i, 3, _T("男"));
}