现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

可编辑子项的CListCtrl类

2012-09-07 07:01 工业·编程 ⁄ 共 7104字 ⁄ 字号 暂无评论

大家都知道在MFC中通过给CListCtrl设置LVS_EDITLABELS属性,并且在程序中响应控件的LVN_ENDLABELEDIT消息可以修改列表控件每一行的第一项,也就是主项(Item)。

void CEditListCtrlSampleDlg::OnEndlabeleditList1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	// TODO: Add your control notification handler code here
	
	*pResult = TRUE;   //TRUE值表示可以修改主项,FALSE值表示不修改主项
}
但是让人郁闷的是,微软留了一手,CListCtrl不支持直接修改子项(SubItem)。下面的代码实现直接修改子项的功能。

具体思路如下:

创建一个CEDIT 编辑框,然后把编辑框覆盖当前的 subitem 上,并且使编辑框获取焦点。当编辑框失去焦点时,把编辑框里的文字,显示到 listctrl 控件上,就可以了。为了能够使控件知道何时显示编辑框中的文字,所以还有重写编辑框,当编辑框失去焦点时,通过消息通知 listctrl 控件。

代码如下:
1.新建一个CItemEdit类,该类继承自CEdit
ItemEdit.h文件的代码如下:
class CItemEdit : public CEdit
{
// Construction
public:
	CItemEdit();

// Attributes
public:

// Operations
public:

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

// Implementation
public:
	virtual ~CItemEdit();

	// Generated message map functions
protected:
	//{{AFX_MSG(CItemEdit)
	afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos);
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()

public:
	int m_iXPos; 
};
ItemEdit.cpp文件的代码如下:
#include "ItemEdit.h"

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

/////////////////////////////////////////////////////////////////////////////
// CItemEdit

CItemEdit::CItemEdit()
{
}

CItemEdit::~CItemEdit()
{
}


BEGIN_MESSAGE_MAP(CItemEdit, CEdit)
	//{{AFX_MSG_MAP(CItemEdit)
	ON_WM_WINDOWPOSCHANGING()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CItemEdit message handlers

void CItemEdit::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
{
	lpwndpos->x = m_iXPos;
	CEdit::OnWindowPosChanging(lpwndpos);
	
	// TODO: Add your message handler code here
	
}

新建一个CEditListCtrl类,该类继承自CListCtrl,并包含了一个CItemEdit对象的成员变量。

EditListCtrl.h文件的代码如下:

#include "ItemEdit.h"
/////////////////////////////////////////////////////////////////////////////
// CEditListCtrl window
class CEditListCtrl : public CListCtrl
{
// Construction
public:
CEditListCtrl();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEditListCtrl)
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CEditListCtrl();
// Generated message map functions
protected:
//{{AFX_MSG(CEditListCtrl)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult);//开始编辑时的需处理的内容
afx_msg void OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult);//结束编辑时需处理的内容
afx_msg void OnPaint();//控件重绘时需要处理的内容
afx_msg void OnKillFocus(CWnd* pNewWnd);//控件失去焦点需做的处理
//}}AFX_MSG
afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); //自定义控件的绘制
DECLARE_MESSAGE_MAP()
private:
int m_iItem;
int m_iSubItem;
BOOL m_bFocus;
BOOL m_bHighLight;
CItemEdit m_edtItemEdit;
};

EditListCtrl.cpp文件的代码如下所示:

#include "EditListCtrl.h"

CEditListCtrl::CEditListCtrl()
{
m_iItem = -1;
m_iSubItem = -1;
m_bFocus = FALSE;
m_bHighLight = FALSE;
}
CEditListCtrl::~CEditListCtrl()
{
}
BEGIN_MESSAGE_MAP(CEditListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CEditListCtrl)
ON_WM_LBUTTONDOWN()
ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginlabeledit)
ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndlabeledit)
ON_WM_PAINT()
ON_WM_KILLFOCUS()
//}}AFX_MSG_MAP
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CEditListCtrl message handlers
void CEditListCtrl::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLVCUSTOMDRAW *pNMLVCustomDraw = (NMLVCUSTOMDRAW*) pNMHDR;

*pResult = CDRF_DODEFAULT; //NULL
if ( pNMLVCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT )
{
*pResult = CDRF_NOTIFYITEMDRAW;
}
else if( pNMLVCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
*pResult = CDRF_NOTIFYSUBITEMDRAW;
}
else if ( pNMLVCustomDraw->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT))
{
int iItem = (int)pNMLVCustomDraw->nmcd.dwItemSpec;
int iSubItem = pNMLVCustomDraw->iSubItem;
CDC *pDC = CDC::FromHandle(pNMLVCustomDraw->nmcd.hdc);
CString strItemText = GetItemText(iItem, iSubItem);
CRect rcItem, rcText;
GetSubItemRect(iItem, iSubItem, LVIR_LABEL, rcItem);
rcText = rcItem;
CSize size = pDC->GetTextExtent(strItemText);
if (strItemText == _T(""))
{
size.cx = 41;
}
//设置文本高亮矩形
rcText.left += 4;
rcText.right = rcText.left + size.cx + 6;
if ( rcText.right > rcItem.right )
{
rcText.right = rcItem.right;
}
COLORREF crOldTextColor = pDC->GetTextColor();
if ( m_bFocus )
{
if ( (m_iItem == iItem) && (m_iSubItem == iSubItem))
{
if ( m_bHighLight )
{
pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
pDC->FillSolidRect(&rcText, ::GetSysColor(COLOR_HIGHLIGHT));
}
pDC->DrawFocusRect(&rcText);
}
}
rcItem.left += 6;
pDC->DrawText(strItemText, &rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP);
pDC->SetTextColor(crOldTextColor);
*pResult = CDRF_SKIPDEFAULT;
}
}
void CEditListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_bFocus = TRUE;
LVHITTESTINFO lvhit;
lvhit.pt = point;
int item = SubItemHitTest(&lvhit);

if ( item != -1 && (lvhit.flags & LVHT_ONITEM))
{
CListCtrl::OnLButtonDown(nFlags, point);
if ( m_bHighLight && m_iItem == lvhit.iItem && m_iSubItem == lvhit.iSubItem )
{
//第二次单击
EditLabel(m_iItem);
return;
}
else
{
//第一次单击
m_iItem = lvhit.iItem;
m_iSubItem = lvhit.iSubItem;
m_bHighLight = TRUE;
}
}
else
{
if ( m_edtItemEdit.m_hWnd == NULL)
{
m_bHighLight = FALSE;
}
CListCtrl::OnLButtonDown(nFlags, point);
}
Invalidate();
}
void CEditListCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
// TODO: Add your control notification handler code here
if ( m_iSubItem >= 0)
{
ASSERT(m_iItem == pDispInfo->item.iItem);
CRect rcSubItem;
GetSubItemRect(pDispInfo->item.iItem, m_iSubItem, LVIR_BOUNDS, rcSubItem);
HWND hWnd = (HWND) SendMessage(LVM_GETEDITCONTROL);
ASSERT( hWnd != NULL);
VERIFY(m_edtItemEdit.SubclassWindow(hWnd));
m_edtItemEdit.m_iXPos = rcSubItem.left + 4;
m_edtItemEdit.SetWindowText(GetItemText(pDispInfo->item.iItem, m_iSubItem));
}
*pResult = 0;
}
void CEditListCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
// TODO: Add your control notification handler code here
LV_ITEM *plvItem = &pDispInfo->item;

if ( m_iSubItem >= 0 )
{
if ( plvItem->pszText != NULL )
{
SetItemText( plvItem->iItem, m_iSubItem, plvItem->pszText);
}

VERIFY(m_edtItemEdit.UnsubclassWindow() != NULL);
*pResult = 0;
}

CRect rect;
GetWindowRect(&rect);
CPoint point;
::GetCursorPos(&point);
if ( !rect.PtInRect(point))
{
m_iItem = -1;
m_iSubItem = -1;
m_bFocus = FALSE;
m_bHighLight = FALSE;
}
}
void CEditListCtrl::OnPaint()
{
//CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here

// Do not call CListCtrl::OnPaint() for painting messages
if ( m_iSubItem >= 0 && m_edtItemEdit.m_hWnd )
{
CRect rect;
CRect rcEdit;
m_edtItemEdit.GetWindowRect(rcEdit);
ScreenToClient(rcEdit);
GetSubItemRect(m_iItem, m_iSubItem, LVIR_LABEL, rect);

if ( rcEdit.right < rect.right)
{
rect.left = rcEdit.right;
CClientDC dc(this);
dc.FillRect(rect, &CBrush(::GetSysColor(COLOR_WINDOW)));
ValidateRect(rect);
}
}
CListCtrl::OnPaint();
}
void CEditListCtrl::OnKillFocus(CWnd* pNewWnd)
{
CListCtrl::OnKillFocus(pNewWnd);

// TODO: Add your message handler code here
CRect rect;
GetWindowRect(&rect);
CPoint point;
::GetCursorPos(&point);
if ( !rect.PtInRect(point) && GetParent()->GetFocus() != NULL)
{
m_iItem = -1;
m_iSubItem = -1;
m_bFocus = FALSE;
m_bHighLight = FALSE;
Invalidate();
}
}
void CEditListCtrl::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
ModifyStyle(0, LVS_EDITLABELS);
CListCtrl::PreSubclassWindow();
}

使用CEditListCtrl类生成的ListCtrl就可以编辑其子项了。

给我留言

留言无头像?