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 = 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