MFC虚拟列表 + 指定行设置颜色 + 在表格item中添加按钮

主要知识点就是mfc CListCtrl的LVN_GETDISPINFO和NM_CUSTOMDRAW消息处理
虚拟列表简单理解:我们维护自己想要展示的数据,系统根据展示情况来取数据,我们只要专注维护数据就可以了.

先放个效果图:
在这里插入图片描述
继承CMFCButton和CListCtrl

class CButtonEx : public CMFCButton
{
	DECLARE_DYNAMIC(CButtonEx)
public:
	CButtonEx(int iItem, int iSubItem, CRect rect);
	virtual ~CButtonEx();

	int m_iItem;

protected:
	DECLARE_MESSAGE_MAP()
public:
	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
};

class CVirualListCtrl : public CListCtrl
{
private:
	CString m_strKey;
	vector<CString> m_vtrData;
	int m_iItemCounts;
	int m_iSelLine;
	UINT m_uId;
	map<int, CButtonEx*> m_btnMap;

public:
	CVirualListCtrl();
	~CVirualListCtrl();

	DECLARE_MESSAGE_MAP()
public:
	BOOL setStringKey(CString);//设置一个特定内容,凡有是这个内容的行显示为红色
	BOOL setVtrData(vector<CString>& vtrData);
	afx_msg void OnLvnGetdispinfoList(NMHDR *pNMHDR, LRESULT *pResult);//处理
	afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);//处理自绘事件
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
	virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);

	//添加在item中按钮
	BOOL CreateItemButton(int iSubItem);
	void UpdateListCtrlButtonText(int iItem);
	void ReleaseItemButton();
};

源文件:

//
//ListCtrl中的按钮
IMPLEMENT_DYNAMIC(CButtonEx, CMFCButton)
CButtonEx::CButtonEx(int iItem, int iSubItem, CRect rect)
{
	m_iItem = iItem;
}

CButtonEx::~CButtonEx()
{
}

BEGIN_MESSAGE_MAP(CButtonEx, CMFCButton)
END_MESSAGE_MAP()

LRESULT CButtonEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	// TODO: 在此添加专用代码和/或调用基类
	switch (message)
	{
	case WM_MOUSEMOVE:
	case WM_LBUTTONDOWN:
	case WM_LBUTTONDBLCLK:
		return TRUE;
	case WM_LBUTTONUP:
	{
		CString strBuff;
		strBuff.Format("当前行:%d",m_iItem);
		MessageBox(strBuff, "提示", MB_OK);
	}
		return TRUE;
	}

	return CMFCButton::WindowProc(message, wParam, lParam);
}

//

//
//CVirualListCtrl
CVirualListCtrl::CVirualListCtrl()
{
	m_iItemCounts = 23;
	m_uId = WM_USER + 1000;
}

CVirualListCtrl::~CVirualListCtrl()
{
	ReleaseItemButton();
}

BEGIN_MESSAGE_MAP(CVirualListCtrl, CListCtrl)
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, &CVirualListCtrl::OnLvnGetdispinfoList)
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CVirualListCtrl::OnNMCustomdraw)
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()

BOOL CVirualListCtrl::setStringKey(CString strKey)
{
	if (strKey.IsEmpty())
	{
		return FALSE;
	}

	m_strKey = strKey;

	return TRUE;
}

BOOL CVirualListCtrl::setVtrData(vector<CString>& vtrData)
{
	if (vtrData.empty())
	{
		return FALSE;
	}

	m_vtrData = vtrData;
	SetItemCountEx(m_vtrData.size());

	return TRUE;
}

void CVirualListCtrl::OnLvnGetdispinfoList(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码
	LV_ITEM* pItem = &(pDispInfo)->item;

	if (pItem->mask & LVIF_TEXT)
	{
		//pItem->iSubItem为列号
		switch (pItem->iSubItem)
		{
		case 0:
		{
			//pItem->iItem为行号
			lstrcpyn(pItem->pszText, m_vtrData[pItem->iItem], pItem->cchTextMax);
		}
		break;
		case 1:
		{
			if (0 == pItem->iItem)
			{
				lstrcpyn(pItem->pszText, "污源子的小故事", pItem->cchTextMax);
			}
			else if (5 == pItem->iItem)
			{
				lstrcpyn(pItem->pszText, "污源子的小故事", pItem->cchTextMax);
			}
			else
			{
				lstrcpyn(pItem->pszText, "污源子", pItem->cchTextMax);
			}
		}
		break;
		case 2:
		{
			lstrcpyn(pItem->pszText, "虚拟列表", pItem->cchTextMax);
		}
		break;
		case 3:
		{
			UpdateListCtrlButtonText(pItem->iItem);
		}
		break;
		default:
			break;
		}
	}
}
void CVirualListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	*pResult = CDRF_DODEFAULT;
	NMLVCUSTOMDRAW * lplvdr = (NMLVCUSTOMDRAW*)pNMHDR;
	NMCUSTOMDRAW &nmcd = lplvdr->nmcd;

	switch (lplvdr->nmcd.dwDrawStage)
	{
		case CDDS_PREPAINT:
		{
			//设置自定义绘制
			*pResult = CDRF_NOTIFYITEMDRAW;	
		}
		break;
		case CDDS_ITEMPREPAINT:
		{
			//绘制item
			//item的text判断是否是需要设置使用红色绘制
			if (m_strKey == GetItemText((int)nmcd.dwItemSpec, 1))
			{
				lplvdr->clrText = RGB(0xff, 0, 0);
				*pResult = CDRF_DODEFAULT;
			}
		}
		break;
		default:
			break;
	}
}
void CVirualListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (nChar)
	{
	case VK_DOWN:
	{
		POSITION pos = GetFirstSelectedItemPosition();
		int iItem = GetNextSelectedItem(pos) + 1;

		//可以根据上下移动发送消息处理其他界面
		//::PostMessage(GetParent()->GetSafeHwnd(), WM_KEY_DOWN, (WPARAM)iItem, 0);
	}
	break;
	case VK_UP:
	{
		POSITION pos = GetFirstSelectedItemPosition();
		int iItem = GetNextSelectedItem(pos) - 1;

		//::PostMessage(GetParent()->GetSafeHwnd(), WM_KEY_UP, (WPARAM)iItem, 0);
	}
	break;
	}

	CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
BOOL CVirualListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	//限制表头拖动
	NMHEADER* pNMHeader = (NMHEADER*)lParam;
	if (((pNMHeader->hdr.code == HDN_BEGINTRACKW) |
		(pNMHeader->hdr.code == HDN_DIVIDERDBLCLICKW)))
	{
		*pResult = TRUE;
		return TRUE;
	}

	return CListCtrl::OnNotify(wParam, lParam, pResult);
}
BOOL CVirualListCtrl::CreateItemButton(int iSubItem)
{
	for (int i = 0; i < m_iItemCounts; i++)
	{
		//根据item设置按钮大小
		CRect rect;
		GetSubItemRect(i, iSubItem, LVIR_BOUNDS, rect);
		rect.bottom = rect.top + 18;
		//创建按钮
		CButtonEx* pButton = new CButtonEx(i, iSubItem, rect);

		pButton->Create(nullptr, WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, rect, this, m_uId);
		//pButton->SetFont(&m_btnFont);

		m_uId++;
		//垂直创建
		m_btnMap.insert(make_pair(i, pButton));
	}

	return TRUE;
}
void CVirualListCtrl::UpdateListCtrlButtonText(int iItem)
{
	int nItem = iItem - GetTopIndex();

	if (nItem >= m_btnMap.size() || nItem < 0)
	{
		return;
	}

	CString strText;
	strText.Format(_T("%d"), iItem);
	m_btnMap[nItem]->m_iItem = iItem;
	m_btnMap[nItem]->SetWindowText(strText);
}
void CVirualListCtrl::ReleaseItemButton()
{
	map<int, CButtonEx*>::iterator iter = m_btnMap.begin();

	while (iter != m_btnMap.end())
	{
		delete iter->second;
		iter->second = nullptr;
		iter++;
	}

	m_btnMap.clear();
}
//

调用代码:

	CString strNumber;

	for (int i = 0;i < 3000;i++)
	{
		strNumber.Format("%d", i);
		m_vtrStrNumber.push_back(strNumber);
	}

	initVirualtListCtrl();

initVirualtListCtrl函数

void CMFCTestDlg::initVirualtListCtrl()
{
	CRect rectWin, rectList;
	GetClientRect(&rectWin);

	rectList = rectWin;
	rectList.bottom -= 40;

	//样式设置为report,使用虚拟列表一定要设置LVS_OWNERDATA属性
	m_listCtrlTwo.Create(WS_VISIBLE | WS_CHILD | LVS_REPORT | LVS_OWNERDATA, rectList, this, IDC_LIST2);

	//插入列和设置列宽
	int iColOneWidth = 40;
	m_listCtrlTwo.InsertColumn(0, "行号", LVCFMT_RIGHT, iColOneWidth);
	m_listCtrlTwo.InsertColumn(1, "第一列", LVCFMT_CENTER, (rectList.Width() - iColOneWidth) / 3);
	m_listCtrlTwo.InsertColumn(2, "第二列", LVCFMT_CENTER, (rectList.Width() - iColOneWidth) / 3);
	m_listCtrlTwo.InsertColumn(3, "第三列", LVCFMT_CENTER, (rectList.Width() - iColOneWidth) / 3 - 10);
	//设置列表的显示样式
	m_listCtrlTwo.SetExtendedStyle(m_listCtrlTwo.GetExStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
	// 设置自定义属性
	m_listCtrlTwo.setStringKey("污源子的小故事");
	m_listCtrlTwo.CreateItemButton(3);
	m_listCtrlTwo.setVtrData(m_vtrStrNumber);
}
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值