CTreeCtrl更改-/+展开按钮颜色(非完全自绘,可自定义展开按钮样式)

先上一张效果图,有兴趣就继续看,没兴趣就闪了\(^o^)/~。

 先贴一个链接。 CTreeCtrl加背景 。 我是在此基础上加的功能,所谓站在巨人的肩膀上看世界。

实现步骤:

1、增加 =NM_CUSTOMDRAW 消息映射

类视图->类上右键

消息映射

增加消息映射后

void CMyTreeCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);

	*pResult = 0;
}

2、增加绘制项(也就是树控件的节点)结束处理,利用 CDRF_NOTIFYPOSTPAINT 定制消息通知

void CMyTreeCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	//LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
	LPNMTVCUSTOMDRAW pNMCD = reinterpret_cast<LPNMTVCUSTOMDRAW>(pNMHDR);
	LPNMCUSTOMDRAW custom_draw = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
	switch (pNMCD->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		*pResult = CDRF_NOTIFYITEMDRAW ;//订阅绘制项前通知
		return;
	case CDDS_ITEMPREPAINT:
		*pResult = CDRF_NOTIFYPOSTPAINT;//订阅绘制结束通知
		return;
	case CDDS_ITEMPOSTPAINT:
        //此处处理项绘制结束的额外处理
		break;
	}
	*pResult = 0;
}

3、获得 -/+ 按钮的位置 

利用GetIndent()获得缩进增量,该增量需要乘以一个变量才能获得-/+按钮的实际区域,

这个需要乘的变量就是 NMTVCUSTOMDRAW::iLevel

4、我们目前有个问题是:

当 NMTVCUSTOMDRAW::nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT时,

NMTVCUSTOMDRAW::iLevel的值始终为0,

所以,需要在NMTVCUSTOMDRAW::nmcd.dwDrawStage == CDDS_ITEMPREPAINT时,

保存好iLevel

因为项不止一个,所以我定义了一个链表来保存这个值 :

std::list<std::pair<HTREEITEM, int> > m_items;

附上最后修正后的OnNMCustomdraw()的实现

void CMyTreeCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	//LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
	LPNMTVCUSTOMDRAW pNMCD = reinterpret_cast<LPNMTVCUSTOMDRAW>(pNMHDR);
	LPNMCUSTOMDRAW custom_draw = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
	switch (pNMCD->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		*pResult = CDRF_NOTIFYITEMDRAW ;//订阅绘制项前通知
		m_items.clear();
		return;
	case CDDS_ITEMPREPAINT://项绘制前通知
		pNMCD->clrText = RGB(0, 255, 0); //修改文字颜色
		*pResult = CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;//订阅绘制结束通知
		m_items.push_back(std::make_pair((HTREEITEM)pNMCD->nmcd.dwItemSpec, pNMCD->iLevel));
		return;
	case CDDS_ITEMPOSTPAINT://项绘制结束通知
	{
		UINT unt = GetIndent();
		HTREEITEM htreeitem = (HTREEITEM)pNMCD->nmcd.dwItemSpec;
		auto itfind = std::find_if(m_items.begin(), m_items.end(), [&](const std::pair<HTREEITEM, int>&val ) 
		{
			return val.first == htreeitem;
		});
		if (itfind != m_items.end())
		{
			CRect button_rect = custom_draw->rc;
			button_rect.right = button_rect.left + unt;
			int off = unt*itfind->second;
			button_rect.DeflateRect(off, 0, -off, 0);
			CString button_content = GetChildItem(htreeitem) ? _T("√"):_T("×");
			::SetTextColor(custom_draw->hdc, RGB(255,0,0));
			DrawText(custom_draw->hdc, button_content, button_content.GetLength(), button_rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			*pResult = CDRF_SKIPDEFAULT;
			return;
		}
	}
		break;
	}
	*pResult = 0;
}

作为程序猿,说那么多都是空的,附上demo源码才是王道

不过我不知道怎么附加文件(想把工程打包整上来) 

附上.h和.cpp的全部内容吧

MyTreeCtrl.h

#pragma once
#include <list>

// CMyTreeCtrl

class CMyTreeCtrl : public CTreeCtrl
{
private:
	std::list<std::pair<HTREEITEM, int> > m_items;
	// Construction
public:
	CMyTreeCtrl();

	// Attributes
public:
	BOOL SetBKImage(LPCTSTR LpszResource);

	// Operations
public:

	// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CMyTreeCtrl)
protected:
	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
	//}}AFX_VIRTUAL

	// Implementation
public:
	virtual ~CMyTreeCtrl();

	// Generated message map functions
protected:
	CBitmap m_bitmap;
	//{{AFX_MSG(CMyTreeCtrl)
	afx_msg void OnPaint();
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult);
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
};

MyTreeCtrl.cpp

// MyTreeCtrl.cpp : 实现文件
//

#include "stdafx.h"
#include "TreeCtrlBKG.h"//这个可以删除 是我的demo工程的主app类(MFC对话框类)
#include "MyTreeCtrl.h"
#include <algorithm>

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

/
// CMyTreeCtrl

CMyTreeCtrl::CMyTreeCtrl()
{
}

CMyTreeCtrl::~CMyTreeCtrl()
{
}


BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl)
	//{{AFX_MSG_MAP(CMyTreeCtrl)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded)
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)
	//}}AFX_MSG_MAP
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMyTreeCtrl::OnNMCustomdraw)
END_MESSAGE_MAP()

/
// CMyTreeCtrl message handlers
BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
{

	// if this is not the first call then delete gdi objects
	if (m_bitmap.m_hObject != NULL)
		m_bitmap.DeleteObject();

	HBITMAP hbmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
		LpszResource, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

	if (hbmp == NULL)
		return FALSE;

	m_bitmap.Attach(hbmp);

	return TRUE;
}

LRESULT CMyTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	// TODO: Add your specialized code here and/or call the base class

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

void CMyTreeCtrl::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	CRect rcclient;
	GetClientRect(&rcclient);

	// create a compatible memory dc 
	CDC memdc;
	memdc.CreateCompatibleDC(&dc);
	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap(&dc, rcclient.Width(), rcclient.Height());
	memdc.SelectObject(&bitmap);

	CWnd::DefWindowProc(WM_PAINT, (WPARAM)memdc.m_hDC, 0);

	CDC maskdc;
	maskdc.CreateCompatibleDC(&dc);
	CBitmap maskbitmap;
	maskbitmap.CreateBitmap(rcclient.Width(), rcclient.Height(), 1, 1, NULL);
	maskdc.SelectObject(&maskbitmap);
	maskdc.BitBlt(0, 0, rcclient.Width(), rcclient.Height(), &memdc,
		rcclient.left, rcclient.top, SRCCOPY);

	CBrush brush;
	brush.CreatePatternBrush(&m_bitmap);
	dc.FillRect(rcclient, &brush);

	memdc.SetBkColor(RGB(0, 0, 0));
	memdc.SetTextColor(RGB(255, 255, 255));
	memdc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &maskdc, rcclient.left, rcclient.top, SRCAND);

	dc.SetBkColor(RGB(255, 255, 255));
	dc.SetTextColor(RGB(0, 0, 0));
	dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &maskdc, rcclient.left, rcclient.top, SRCAND);

	dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &memdc,
		rcclient.left, rcclient.top, SRCPAINT);
	brush.DeleteObject();
}


BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)
{
	// TODO: Add your message handler code here and/or call default
	return TRUE;
}

void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	Invalidate();
	SetRedraw(TRUE);
	*pResult = 0;
}

void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	SetRedraw(FALSE);
	*pResult = 0;
}

void CMyTreeCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	//LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
	LPNMTVCUSTOMDRAW pNMCD = reinterpret_cast<LPNMTVCUSTOMDRAW>(pNMHDR);
	LPNMCUSTOMDRAW custom_draw = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
	switch (pNMCD->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		*pResult = CDRF_NOTIFYITEMDRAW ;//订阅绘制项前通知
		m_items.clear();
		return;
	case CDDS_ITEMPREPAINT://项绘制前通知
		pNMCD->clrText = RGB(0, 255, 0); //修改文字颜色
		*pResult = CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;//订阅绘制结束通知
		m_items.push_back(std::make_pair((HTREEITEM)pNMCD->nmcd.dwItemSpec, pNMCD->iLevel));
		return;
	case CDDS_ITEMPOSTPAINT://项绘制结束通知
	{
		UINT unt = GetIndent();
		HTREEITEM htreeitem = (HTREEITEM)pNMCD->nmcd.dwItemSpec;
		auto itfind = std::find_if(m_items.begin(), m_items.end(), [&](const std::pair<HTREEITEM, int>&val ) 
		{
			return val.first == htreeitem;
		});
		if (itfind != m_items.end())
		{
			CRect button_rect = custom_draw->rc;
			button_rect.right = button_rect.left + unt;
			int off = unt*itfind->second;
			button_rect.DeflateRect(off, 0, -off, 0);
			CString button_content = GetChildItem(htreeitem) ? _T("√"):_T("×");
			::SetTextColor(custom_draw->hdc, RGB(255,0,0));
			DrawText(custom_draw->hdc, button_content, button_content.GetLength(), button_rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			*pResult = CDRF_SKIPDEFAULT;
			return;
		}
	}
		break;
	}
	*pResult = 0;
}

头一回写这玩意,不到之处,还望海涵!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值