首页 > 代码库 > ListCtrl的扩展类EditListCtrl

ListCtrl的扩展类EditListCtrl

该类继承自MFC的CListCtrl类;

实现列可选,多单元格可选,单击选中单元格并能双击编辑,同时也可以设定某一列是否能进行编辑等等。

功能强大,欢迎使用。

<p><span style="font-family: Arial, Helvetica, sans-serif;">头文件:</span></p><p>CEditListCtrl.h</p>
class CEditListCtrl : public CListCtrl
{
	// Construction
public:
	CEditListCtrl();

	// Attributes
public:
	CEdit* m_edit;//指向编辑框
	BOOL m_panduan1;
	UINT Idfrom;
	BOOL * m_isedit;//数组 表明可编辑列号
	//	CEdit* m_edit;//指向编辑框
	int m_subitem;
	int m_item;
	int m_old_item;//在LButtonDown中用来保存起点行数
	int m_old_subitem;//在LButtonDown中用来保存起点列数
	int m_now_item;
	int m_now_subitem;
	//	BOOL DestroyWindow();
	using CListCtrl::DestroyWindow;//重载函数
	BOOL DestroyWindow();
	void SetEditColomn(int col,BOOL edit);

	// Operations
public:
	BOOL m_downmove;
	BOOL m_bCustomDraw;
	int m_nNumberOfRows;
	int m_nNumberOfCols;
	// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CEditListCtrl)
	//}}AFX_VIRTUAL

	// Implementation
public:
	virtual ~CEditListCtrl();

	// Generated message map functions
protected:
	//{{AFX_MSG(CEditListCtrl)
	afx_msg void OnDblclk(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnKeydown(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void onm ouseMove(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
	afx_msg void OnClose();
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()
private:
	void invalidate_grid(int row,int col);
	afx_msg void custom_draw_funtion(NMHDR *pNMHDR, LRESULT *pResult);
};
源文件:

CEditListCtrl.cpp

// EditListCtrl.cpp : implementation file
//

#include "stdafx.h"
//#include "CEditListDlg.h"
#include "EditListCtrl.h"

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

//////////////////////Doctor.W////////////////////////////
// CEditListCtrl
CEditListCtrl::CEditListCtrl()
{
	m_bCustomDraw=TRUE;
	m_now_subitem=-1;
	m_now_item=-1;
	m_old_subitem=-1;
	m_old_item=-1;
	m_nNumberOfRows=0;
	m_nNumberOfCols=0;
	m_downmove=FALSE;
	m_item=-1;
	m_subitem=-1;
	m_edit=NULL;
	m_isedit=NULL;
}

CEditListCtrl::~CEditListCtrl()
{
	if(m_isedit)
		delete [] m_isedit;
	if(m_edit)
		delete m_edit;
}


BEGIN_MESSAGE_MAP(CEditListCtrl, CListCtrl)
	//{{AFX_MSG_MAP(CEditListCtrl)
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
	ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
	ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_NOTIFY_REFLECT(NM_SETFOCUS, OnSetfocus)
	ON_NOTIFY_REFLECT(NM_KILLFOCUS, OnKillfocus)
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,custom_draw_funtion)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CEditListCtrl message handlers

void CEditListCtrl::custom_draw_funtion(NMHDR *pNMHDR, LRESULT *pResult)
{

	NMLVCUSTOMDRAW* nmcd=(NMLVCUSTOMDRAW*)pNMHDR;
	*pResult=CDRF_DODEFAULT;

	int row;
	int col;

	switch(nmcd->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		if(m_bCustomDraw)
			*pResult=CDRF_NOTIFYITEMDRAW; // else CDRF_DODEFAULT which stops notyfication messages
		return;

	case CDDS_ITEMPREPAINT:
		*pResult=CDRF_NOTIFYSUBITEMDRAW;
		return;

	case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
		{
			*pResult=0;

			row=nmcd->nmcd.dwItemSpec;
			col=nmcd->iSubItem;

			CString str=GetItemText(row,col);

			CRect rect;
			CDC* pDC=CDC::FromHandle(nmcd->nmcd.hdc);

			if(col>0)
				GetSubItemRect(row,col,LVIR_BOUNDS,rect);
			else
				GetItemRect(row,&rect,LVIR_LABEL);

			UINT uCode=DT_LEFT;
			int olditem,oldsub,nowitem,nowsub;
			olditem=m_old_item;
			nowitem=m_now_item;
			oldsub=m_old_subitem;
			nowsub=m_now_subitem;
			if (m_old_item>m_now_item)
			{
				olditem=m_now_item;
				nowitem=m_old_item;
			}
			if (m_old_subitem>m_now_subitem)
			{
				oldsub=m_now_subitem;
				nowsub=m_old_subitem;
			}
			if( (row>=olditem&&row<=nowitem)&&(col>=oldsub&&col<=nowsub))
			{
				COLORREF kolor=0xffff5f;//0x004e98;//0xffff00;//lanse
				if(0==col || 1==col || 3==col)
				{
					kolor=0xFFA500;//0xc0c0c0;
					if(GetFocus()==this)
						kolor=0xFFBBFF;//0xaa00aa;
					CBrush brush(kolor);
					pDC->FillRect(&rect,&brush);
				}
				else
				{
					if(GetFocus()==this)
						kolor=0xFFA500;//0xff0000;//shenlan;
				}
				CBrush brush(kolor);
				pDC->FillRect(&rect,&brush);
			}
			else
			{
				if(0==col || 1==col || 3==col)
				{
					COLORREF kolor=0xc0c0c0;
					CBrush brush(kolor);
					pDC->FillRect(&rect,&brush);
				}
				else
				{

					COLORREF kolor=0xC1FFC1;//0xfae9d0;//豆沙绿
					CBrush brush(kolor);
					pDC->FillRect(&rect,&brush);	
				}

			}	
			rect.OffsetRect(5,0);
			if (col==3)
			{
				pDC->DrawText(str,&rect,DT_CENTER);
			}
			else
				pDC->DrawText(str,&rect,uCode);


			*pResult=CDRF_SKIPDEFAULT;

			break;
		}
	}
}

void CEditListCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NMITEMACTIVATE* nm=(NMITEMACTIVATE*)pNMHDR;

	m_downmove=FALSE;
	Invalidate();

	if(!m_isedit) return;
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	if(!m_edit)
	{
		m_subitem=pNMListView->iSubItem;
		if(pNMListView->iItem!=m_item)
		{
			m_item=pNMListView->iItem;//标志被单击的项目
			// return;
		}
	}

	*pResult = 0;
}

void CEditListCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NMLVKEYDOWN* nmkd = (NMLVKEYDOWN*)pNMHDR;

	switch(nmkd->wVKey)
	{
	case VK_LEFT: 
		m_old_subitem--;
		if(m_old_subitem<0)
			m_old_subitem=0;
		invalidate_grid(m_old_item,m_old_subitem+1);
		Invalidate();
		break;
	case VK_RIGHT:
		m_old_subitem++;
		if(m_old_subitem>GetHeaderCtrl()->GetItemCount()-1)
			m_old_subitem=GetHeaderCtrl()->GetItemCount()-1;
		invalidate_grid(m_old_item,m_old_subitem-1);
		Invalidate();
		break;

	case VK_UP:   
		m_old_item--;
		if(m_old_item<0)
			m_old_item=0;
		invalidate_grid(m_old_item+1,m_old_subitem);
		break;

	case VK_DOWN: 
		m_old_item++;
		if(m_old_item>GetItemCount()-1)
			m_old_item=GetItemCount()-1;
		invalidate_grid(m_old_item-1,m_old_subitem);
		break;
	case VK_PRIOR:
		invalidate_grid(m_old_item,m_old_subitem);
		m_old_item=0;
		break;
	case VK_NEXT:
		invalidate_grid(m_old_item,m_old_subitem);
		m_old_item=GetItemCount()-1;
		break;
	case VK_HOME:
		invalidate_grid(m_old_item,m_old_subitem);
		m_old_subitem=0;

		if(GetKeyState(VK_CONTROL)<0)
			m_old_item=0;

		SetItemState(m_old_item,LVIS_FOCUSED,LVIS_FOCUSED);
		*pResult = CDRF_SKIPDEFAULT;
		invalidate_grid(m_old_item,m_old_subitem);
		return;
		break;
	case VK_END:
		invalidate_grid(m_old_item,m_old_subitem);
		m_old_subitem=GetHeaderCtrl()->GetItemCount()-1;
		if(GetKeyState(VK_CONTROL)<0)
			m_old_item=GetItemCount()-1;

		SetItemState(m_old_item,LVIS_FOCUSED,LVIS_FOCUSED);

		*pResult=CDRF_SKIPDEFAULT;
		invalidate_grid(m_old_item,m_old_subitem);
		return;
	}

	*pResult = 0;
}

void CEditListCtrl::invalidate_grid(int row, int col)
{
	CRect r;

	if(col==0 || col==1 || col==3)
		GetItemRect(row,&r,LVIR_LABEL);
	else
		GetSubItemRect(row,col,LVIR_BOUNDS,r);
	m_now_item=m_old_item;
	m_now_subitem=m_old_subitem;
	InvalidateRect(&r);
}


void CEditListCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if (m_downmove)
	{
		POINT pt=point;
		UINT flags;
		//	ClientToScreen(&pt);
		//	CImageList::DragMove(pt);
		LVHITTESTINFO lvhti;
		lvhti.pt=point;
		m_now_item=HitTest(pt,&flags);
		m_now_subitem=SubItemHitTest(&lvhti);
		m_now_subitem=lvhti.iSubItem;
		Invalidate();
	}
	CListCtrl::OnMouseMove(nFlags, point);
}

void CEditListCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_downmove=FALSE;

	CListCtrl::OnLButtonUp(nFlags, point);
}

void CEditListCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default

	//	invalidate_grid(m_item,m_subitem);

	m_downmove=TRUE;
	POINT pt=point;
	UINT flags;
	//	ClientToScreen(&pt);
	//	CImageList::DragMove(pt);
	m_old_item=HitTest(pt,&flags);
	LVHITTESTINFO lvhti;
	lvhti.pt=point;
	m_old_subitem=SubItemHitTest(&lvhti);
	m_old_subitem=lvhti.iSubItem;
	m_now_item=m_old_item;
	m_now_subitem=m_old_subitem;

	if(m_edit)
	{
		m_edit->DestroyWindow();
		m_edit=NULL;
	}

	//m_edit->ShowWindow(SW_HIDE);
	CListCtrl::OnLButtonDown(nFlags, point);
}
void CEditListCtrl::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult) 
{
	// TODO: Add your control notification handler code here
	if(m_edit)
	{//将编辑框中的数据写回对应的子项目中
		UpdateData( );
		CString str;
		m_edit->GetWindowText(str);
		// MessageBox(str);
		SetItemText(m_item,m_subitem,str);
		delete m_edit;
		m_edit=NULL;
	}
	*pResult = 0;
}
void CEditListCtrl::OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult) 
{
	// TODO: Add your control notification handler code here

	Invalidate();
	*pResult = 0;
}

void CEditListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default

	//水平滚动时,移动已显示的编辑框
	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
	LRESULT* pResult=new LRESULT;
	if(m_edit)  OnClick((NMHDR*)this,pResult) ;

}

void CEditListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default

	//垂直滚动时,移动已显示的编辑框。
	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
	LRESULT* pResult=new LRESULT;
	if(m_edit)
	{
		RECT m_itemrect,m_headrect;
		GetItemRect(m_item ,&m_itemrect,2);
		GetHeaderCtrl()->GetWindowRect(&m_headrect);
		if(m_itemrect.top<m_headrect.bottom-m_headrect.top) 
		{
			RECT m_rect;
			m_edit->GetWindowRect(&m_rect);
			m_edit->MoveWindow(m_rect.left,-(m_rect.bottom-m_rect.top),m_rect.right,0);
		}
		else  
		{
			OnClick((NMHDR*)this,pResult) ;
		}
	}
}

void CEditListCtrl::SetEditColomn(int col, BOOL edit)
{
	//设置允许直接进行编辑的列
	if(!m_isedit)
	{
		int len=GetHeaderCtrl()->GetItemCount();
		m_isedit=new BOOL[len];
		for(int i=0;i<len;i++)//初始化m_isedit。
			m_isedit[i]=FALSE;
	}
	m_isedit[col]=edit;
}
void CEditListCtrl::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
{
	// TODO: Add your control notification handler code here
	int i;
	if(!m_isedit) return;
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	if(!m_edit)
	{
		m_subitem=pNMListView->iSubItem;
		if(pNMListView->iItem!=m_item)
		{
			m_item=pNMListView->iItem;//标志被单击的项目
			// return;
		}
	}
	if(!m_isedit[m_subitem])//若当前列不允许直接编辑,则返回 
		return;
	RECT m_itemrect,m_r;
	GetItemRect(m_item ,&m_itemrect,2);
	GetItemRect(0 ,&m_r,2);
	int m_height=m_itemrect.bottom -m_itemrect.top ;
	int x=m_r.left ,y=m_r.top,cx,cy;//(x,y,cx,cy)为编辑框显示的位置
	for(i=0;i< m_item;i++)
		y+=m_height;
	cy=y+m_height;
	for(i=0;i<m_subitem;i++)
		x+=GetColumnWidth(i);
	cx=x+GetColumnWidth(i);
	if(m_edit)//若编辑框已存在。
	{
		CString s1;
		s1.Format (_T("%d %d %d %d"),x,y,cx,cy);
		m_edit->MoveWindow(x-4,y,cx-x-4,cy-y);//移动到当前子项目的位置。
		Invalidate();//刷新屏幕。
		return;
	}  
	//若编辑框不存在,则创建编辑框,并在当前子项目处显示编辑框。
	CRect rect(x-4,y,cx-4,cy);
	m_edit=new CEdit();
	m_edit->Create (WS_CHILD|WS_VISIBLE|WS_BORDER,rect,this,ID_LISTEDIT);
	SetWindowLong(m_edit->m_hWnd, GWL_STYLE,GetWindowLong(m_edit->m_hWnd, GWL_STYLE) | ES_NUMBER);//控制只允许输入数字
	CString str=GetItemText (pNMListView->iItem,pNMListView->iSubItem);
	m_edit->UpdateData(0);
	m_edit->SetWindowText(str); 
	DWORD  dwSel = m_edit->GetSel();   
	m_edit->SetSel(HIWORD(dwSel), -1);   
	m_edit->ShowWindow (SW_SHOW);//显示编辑框。
	m_edit->SetFocus ();

	*pResult = 0;
}

BOOL CEditListCtrl::DestroyWindow()
{
	delete [] m_isedit; 
	return CListCtrl::DestroyWindow();
}

void CEditListCtrl::OnClose() 
{
	// TODO: Add your message handler code here and/or call default
	if(m_edit)
		delete m_edit;
	delete [] m_isedit;
	CListCtrl::OnClose();
}