前段时间一个VC++6的开发任务中,打算在CListCtrl控件中添加编辑框和下拉列表框,以便扩展下拉列表框的功能.因为VC++6的CListCtrl控件默认行为只能浏览,不能编辑每一项,而且每一下也没有下拉列表框的样式,要改变这种样式,只能自己编码,因自己水平有限,只能上网求助.上网搜索一翻,终于找到!是一个外国人写的,真得很佩服他的水平,通过代码可以看出他对VC的熟悉程度.
解决方法就是从CListCtrl派生自己的新类,在自己得派生类里添加这些功能,并添加相应的事件响应函数,这里不多说了,列出源文件中的代码,请大家自己琢磨吧.
头文件:
#if !defined(AFX_MYLISTCTRL_H__D5DCAA3F_54C1_4B6B_85FD_C36648DDA223__INCLUDED_)
#define AFX_MYLISTCTRL_H__D5DCAA3F_54C1_4B6B_85FD_C36648DDA223__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MyListCtrl.h : header file
//
//#define MAX_LISTCTRL_COLUMNS 33
#include <afxtempl.h>
class CInPlaceCombo;
class CInPlaceEdit;
#define WM_VALIDATE WM_USER+0X7FFD
#define WM_SET_ITEMS WM_USER+0X7FFC
/////////////////////////////////////////////////////////////////////////////
// CMyListCtrl window
class CMyListCtrl : public CListCtrl
{
// Construction
public:
//typedef enum {MODE_READONLY,MODE_DIGITAL_EDIT,MODE_TEXT_EDIT,MODE_COMBO} COMBOLISTCTRL_COLUMN_MODE;
CMyListCtrl();
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyListCtrl)
//}}AFX_VIRTUAL
// Implementation
public:
void EnableHScroll(bool bEnable=TRUE);
void EnableVScroll(bool bEnable=TRUE);
void SetValidEditCtrlCharacters(CString& rstrValidCharacters);
void SetReadOnlyColumns(int iColumnIndex,bool bSet=TRUE);
void SetComboColumns(int iColumnIndex,bool bSet=TRUE);
virtual ~CMyListCtrl();
// Generated message map functions
protected:
//{{AFX_MSG(CMyListCtrl)
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:
void ScrollToView(int iColumnIndex,CRect& obCellRect);
bool IsReadOnly(int iColumnIndex);
bool IsCombo(int iColumnIndex);
void CalculateCellRect(int iColumnIndex,int iRowIndex,CRect& robCellRect);
CInPlaceEdit* ShowInPlaceEdit(int iRowIndex,int iColumnIndex,CString& rstrCurSelection);
CInPlaceCombo* ShowInPlaceList(int iRowIndex,int iColumnIndex,CStringList& rComboItemsList,
CString strCurSelection="",int iSel=-1);
bool HitTestEx(CPoint & rHitPoint,int * pRowIndex,int * pColumnIndex) const;
CList<int,int> m_ComboSupportColumnsList;
CList<int,int> m_ReadOnlyColumnsList;
CString m_strValidEditCtrlChars;
DWORD m_dwEditCtrlStyle;
DWORD m_dwDropDownCtrlStyle;
//COMBOLISTCTRL_COLUMN_MODE m_modeColumn[MAX_LISTCTRL_COLUMNS];
//CString m_strValidChars[MAX_LISTCTRL_COLUMNS];
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MYLISTCTRL_H__D5DCAA3F_54C1_4B6B_85FD_C36648DDA223__INCLUDED_)
实现文件:
// MyListCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "J2CPS.h"
#include "MyListCtrl.h"
#include "InPlaceCombo.h"
#include "InPlaceEdit.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define FIRST_COLUMN 0
#define MIN_COLUMN_WIDTH 10
#define MAX_DROP_DOWN_ITEM_COUNT 10
/////////////////////////////////////////////////////////////////////////////
// CMyListCtrl
CMyListCtrl::CMyListCtrl()
{
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;
}
CMyListCtrl::~CMyListCtrl()
{
CInPlaceCombo::DeleteInstance();
CInPlaceEdit::DeleteInstance();
}
BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CMyListCtrl)
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()
/////////////////////////////////////////////////////////////////////////////
// CMyListCtrl message handlers
bool CMyListCtrl::HitTestEx(CPoint &rHitPoint, int *pRowIndex, int *pColumnIndex) const
{
if(!pRowIndex || !pColumnIndex)
return FALSE;
*pRowIndex=HitTest(rHitPoint,NULL);
if(pColumnIndex)
*pColumnIndex=0;
if((GetWindowLong(m_hWnd,GWL_STYLE) & LVS_TYPEMASK)!=LVS_REPORT)
return FALSE;
CHeaderCtrl * pHeader=(CHeaderCtrl *)GetDlgItem(0);
int iColumnCount=pHeader->GetItemCount();
CRect obCellRect;
GetItemRect(*pRowIndex,&obCellRect,LVIR_BOUNDS);
if(obCellRect.PtInRect(rHitPoint))
{
for(*pColumnIndex=0;*pColumnIndex<iColumnCount;(*pColumnIndex)++)
{
int iColWidth=GetColumnWidth(*pColumnIndex);
if(rHitPoint.x>=obCellRect.left && rHitPoint.x<=(obCellRect.left+iColWidth))
return TRUE;
obCellRect.left+=iColWidth;
}
}
return FALSE;
}
void CMyListCtrl::SetComboColumns(int iColumnIndex, bool bSet)
{
POSITION Pos=m_ComboSupportColumnsList.Find(iColumnIndex);
if((Pos==NULL) && bSet)
{
m_ComboSupportColumnsList.AddTail(iColumnIndex);
}
if((Pos!=NULL) && !bSet)
{
m_ComboSupportColumnsList.RemoveAt(Pos);
}
}
void CMyListCtrl::SetReadOnlyColumns(int iColumnIndex, bool bSet)
{
POSITION Pos=m_ReadOnlyColumnsList.Find(iColumnIndex);
if((Pos==NULL) && bSet)
{
m_ReadOnlyColumnsList.AddTail(iColumnIndex);
}
if((Pos!=NULL) && !bSet)
{
m_ReadOnlyColumnsList.RemoveAt(Pos);
}
}
void CMyListCtrl::SetValidEditCtrlCharacters(CString &rstrValidCharacters)
{
m_strValidEditCtrlChars=rstrValidCharacters;
}
void CMyListCtrl::EnableVScroll(bool bEnable)
{
if(bEnable)
{
m_dwDropDownCtrlStyle|=WS_VSCROLL;
}
else
{
m_dwDropDownCtrlStyle&=~WS_VSCROLL;
}
}
void CMyListCtrl::EnableHScroll(bool bEnable)
{
if(bEnable)
{
m_dwDropDownCtrlStyle|=WS_HSCROLL;
}
else
{
m_dwDropDownCtrlStyle&=~WS_HSCROLL;
}
}
CInPlaceCombo* CMyListCtrl::ShowInPlaceList(int iRowIndex, int iColumnIndex, CStringList &rComboItemsList,
CString strCurSelection, int iSel)
{
if(!EnsureVisible(iRowIndex,TRUE))
{
return NULL;
}
CHeaderCtrl* pHeader=static_cast<CHeaderCtrl*>(GetDlgItem(FIRST_COLUMN));
int iColumnCount=pHeader->GetItemCount();
if(iColumnIndex>=iColumnCount || GetColumnWidth(iColumnIndex)<MIN_COLUMN_WIDTH)
{
return NULL;
}
CRect obCellRect(0,0,0,0);
CalculateCellRect(iColumnIndex,iRowIndex,obCellRect);
int iHeight=obCellRect.Height();
int iCount=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;
CInPlaceCombo* pInPlaceCombo=CInPlaceCombo::GetInstance();
pInPlaceCombo->ShowComboCtrl(m_dwDropDownCtrlStyle,obCellRect,this,0,iRowIndex,iColumnIndex,&rComboItemsList,
strCurSelection,iSel);
return pInPlaceCombo;
}
CInPlaceEdit* CMyListCtrl::ShowInPlaceEdit(int iRowIndex, int iColumnIndex, CString &rstrCurSelection)
{
CInPlaceEdit* pInPlaceEdit=CInPlaceEdit::GetInstance();
CRect obCellRect(0,0,0,0);
CalculateCellRect(iColumnIndex,iRowIndex,obCellRect);
pInPlaceEdit->ShowEditCtrl(m_dwEditCtrlStyle,obCellRect,this,0,iRowIndex,iColumnIndex,
m_strValidEditCtrlChars,rstrCurSelection);
return pInPlaceEdit;
}
void CMyListCtrl::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);
}
bool CMyListCtrl::IsCombo(int iColumnIndex)
{
if(m_ComboSupportColumnsList.Find(iColumnIndex))
{
return TRUE;
}
return FALSE;
}
bool CMyListCtrl::IsReadOnly(int iColumnIndex)
{
if(m_ReadOnlyColumnsList.Find(iColumnIndex))
{
return TRUE;
}
return FALSE;
}
void CMyListCtrl::ScrollToView(int iColumnIndex, CRect &obCellRect)
{
CRect rcClient;
GetClientRect(&rcClient);
int iColumnWidth=GetColumnWidth(iColumnIndex);
int iOffSet=0;
for(int iIndex_=0;iIndex_<iColumnIndex;iIndex_++)
{
iOffSet+=GetColumnWidth(iIndex_);
}
CSize obScrollSize(0,0);
if(((iOffSet+obCellRect.left)<rcClient.left) || ((iOffSet+obCellRect.left)>rcClient.right))
{
obScrollSize.cx=iOffSet+obCellRect.left;
}
else
if((iOffSet+obCellRect.left+iColumnWidth)>rcClient.right)
{
obScrollSize.cx=iOffSet+obCellRect.left+iColumnWidth-rcClient.right;
}
Scroll(obScrollSize);
obCellRect.left-=obScrollSize.cx;
obCellRect.left+=iOffSet;
obCellRect.right=obCellRect.left+iColumnWidth;
}
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);
}
void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
int iColumnIndex=-1;
int iRowIndex=-1;
if(!HitTestEx(point,&iRowIndex,&iColumnIndex))
{
return;
}
CListCtrl::OnLButtonDown(nFlags, point);
if((GetKeyState(VK_SHIFT) & 0X80) || (GetKeyState(VK_CONTROL) & 0X80))
{
return;
}
CString strCurSelection=GetItemText(iRowIndex,iColumnIndex);
if(iRowIndex!=-1)
{
UINT flag=LVIS_FOCUSED;
if((GetItemState(iRowIndex,flag) & flag)==flag)
{
if(GetWindowLong(m_hWnd,GWL_STYLE) & LVS_EDITLABELS)
{
if(IsCombo(iColumnIndex))
{
CStringList obComboItemsList;
GetParent()->SendMessage(WM_SET_ITEMS,(WPARAM)iColumnIndex,(LPARAM)&obComboItemsList);
CInPlaceCombo* pInPlaceComboBox=ShowInPlaceList(iRowIndex,iColumnIndex,obComboItemsList,strCurSelection);
ASSERT(pInPlaceComboBox);
pInPlaceComboBox->SelectString(-1,strCurSelection);
}
else
if(!IsReadOnly(iColumnIndex))
{
CInPlaceEdit* pInPlaceEdit=ShowInPlaceEdit(iRowIndex,iColumnIndex,strCurSelection);
}
}
}
}
}
void CMyListCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
SetItemText(pDispInfo->item.iItem,pDispInfo->item.iSubItem,pDispInfo->item.pszText);
GetParent()->SendMessage(WM_VALIDATE,GetDlgCtrlID(),(LPARAM)pDispInfo);
*pResult = 0;
}
void CMyListCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
if(IsReadOnly(pDispInfo->item.iSubItem))
{
*pResult=1;
return;
}
*pResult = 0;
}
最后,VC真的很不错,功能很强,虽然上手不快,但仔细研究,大家会有收获的.