近期由於項目的要求,需要一個可以編輯的列表控件,由於MFC提供的列表控件只支持第一行可編輯,無法滿足項目需求,故只能自己動手重寫一個列表控件。重寫列表控件的思想為:當點擊列表的某行某列時,在此處創建一個文本框。廢話不多說,切入正題。
首先,你需要從CListCtrl繼承一個類,名字自己取,這裡我取名為CMyListCtrl。其次,從CEdit繼承一個類,取名為CMyEdit。
CMyEdit類的代碼如下:
CMyEdit.h文件
#pragma once
#include "afxwin.h"
#define WM_USER_EDIT_END (WM_USER+1000)//編輯文本框時給列表發送的消息
class CMyEdit :
public CEdit
{
public:
CMyEdit(void);
~CMyEdit(void);
virtual BOOL PreTranslateMessage(MSG* pMsg);//消息重載函數
afx_msg void OnChange();//文本框的值改變消息
protected:
DECLARE_MESSAGE_MAP()
};
CMyEdit.CPP文件
#include "StdAfx.h"
#include "MyEdit.h"
CMyEdit::CMyEdit(void)
{
}
CMyEdit::~CMyEdit(void)
{
}
BEGIN_MESSAGE_MAP(CMyEdit,CEdit)
ON_CONTROL_REFLECT(EN_CHANGE, OnChange)//這裡為消息反射
END_MESSAGE_MAP()
BOOL CMyEdit::PreTranslateMessage(MSG* pMsg)
{
return CEdit::PreTranslateMessage(pMsg);
}
}
void CMyEdit::OnChange()
{
GetParent()->SendMessage(WM_USER_EDIT_END, WPARAM(m_hWnd), (LPARAM)(m_hWnd));//向列表控件發送消息
}
CMyListCtrl類的代碼如下:
CMyListCtrl.h文件
#pragma once
#include "afxcmn.h"
#include "MyEdit.h"
class CMyListCtrl :public CListCtrl
{
DECLARE_DYNAMIC(CMyListCtrl)
public:
CMyListCtrl(void);
~CMyListCtrl(void);
protected:
DECLARE_MESSAGE_MAP()
public:
//afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg LRESULT OnEditEnd(WPARAM wParam,LPARAM lParam = FALSE);//從CMyEdit類接收來的消息
virtual BOOL PreTranslateMessage(MSG* pMsg);//消息重載
afx_msg void OnVScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar);//垂直滾動條消息
afx_msg void OnHScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar);//水平滾動條消息
afx_msg void OnNMClickList(NMHDR *pNMHDR, LRESULT *pResult);//單擊列表控件
public:
void ShowEdit(bool bShow, int nItem, int nSubItem, CRect rcCtrl);//顯示文本框
CMyEdit m_Edit;
int nItem,nSubItem;//表示行號和列號
};
CMyListCtrl.CPP文件
#include "StdAfx.h"
#include "MyListCtrl.h"
//#define WM_USER_EDIT_END WM_USER+1000
IMPLEMENT_DYNAMIC(CMyListCtrl, CListCtrl)
CMyListCtrl::CMyListCtrl(void)
{
}
CMyListCtrl::~CMyListCtrl(void)
{
}
BEGIN_MESSAGE_MAP(CMyListCtrl,CListCtrl)
//ON_WM_LBUTTONDOWN()
ON_WM_VSCROLL()//水平滾動條消息
ON_WM_HSCROLL()//垂直滾動條消息
ON_MESSAGE(WM_USER_EDIT_END,OnEditEnd)//從CMyEdit類接收來的消息
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,OnNMCustomdrawList)//重繪列表
ON_NOTIFY_REFLECT(NM_CLICK, OnNMClickList)//單擊列表控件
END_MESSAGE_MAP()
BOOL CMyListCtrl::PreTranslateMessage(MSG* pMsg)
{
return CListCtrl::PreTranslateMessage(pMsg);
}
void CMyListCtrl::OnVScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar)
{
if (m_Edit.m_hWnd != NULL)
{
m_Edit.DestroyWindow();
}
CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
Invalidate(FALSE);
}
void CMyListCtrl::OnHScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar)
{
if (m_Edit.m_hWnd != NULL)
{
m_Edit.DestroyWindow();
}
CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
Invalidate(FALSE);
}
void CMyListCtrl::OnNMClickList(NMHDR *pNMHDR, LRESULT *pResult)
{
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
ScreenToClient(&point);
LVHITTESTINFO lvinfo;
lvinfo.pt = point;
CRect rcCtrl;
nItem = CListCtrl::SubItemHitTest(&lvinfo);//得到單擊的點行號
if (nItem == -1)
{
return;
}
nSubItem = lvinfo.iSubItem;//得到列號
CListCtrl::GetSubItemRect(nItem,nSubItem,LVIR_LABEL,rcCtrl);//得到所在區域
ShowEdit(TRUE,nItem,nSubItem,rcCtrl);
}
void CMyListCtrl::ShowEdit(bool bShow, int nItem, int nSubItem, CRect rcCtrl)
{
if (m_Edit.m_hWnd == NULL)
{
m_Edit.Create(ES_AUTOHSCROLL|WS_CHILD|ES_LEFT|ES_WANTRETURN|WS_BORDER,CRect(0,0,0,0),this,0);
m_Edit.ShowWindow(SW_HIDE);
CFont tpFont;
tpFont.CreateStockObject(DEFAULT_GUI_FONT);
m_Edit.SetFont(&tpFont);
tpFont.DeleteObject();
}
if (bShow == TRUE)
{
CString strItem = CListCtrl::GetItemText(nItem,nSubItem);
m_Edit.MoveWindow(&rcCtrl);
m_Edit.ShowWindow(SW_SHOW);
m_Edit.SetWindowText(strItem);
m_Edit.SetFocus();
m_Edit.SetSel(-1);
}
else
{
m_Edit.ShowWindow(SW_HIDE);
}
}
PS:單擊列表控件本應該用afx_msg void OnLButtonDown(UINT nFlags, CPoint point);這裡由於項目需要我用的是afx_msg void OnNMClickList(NMHDR *pNMHDR, LRESULT *pResult);有需要的可自行修改。後續會有通過快捷鍵來編輯列表以及列表內部項的拖動等。第一次寫博客,不足之處望見諒,也希望各位博友一起改進!
聯系你了
聲明的時候
listctrl m_list