CTreeCtrl背景透明完美实现
转载请注明来源:http://www.cnblogs.com/xuesongshu/
这几天有点忙,写完CListCtrl背景透明的实现后没有接着写,今天终于抽个空写上了。程序运行效果请查看我的上篇一博客。、
1、把CTreeCtrl控件子类化。
void CAlphaTreeListDlg::PreInitDialog() { // TODO: 在此添加专用代码和/或调用基类 //其它代码...... m_tree.SubclassDlgItem(IDC_TREE1,this); CDialogEx::PreInitDialog(); }
2、在InitDialog里给CTreeCtrl以做一些初始化的动作
BOOL CAlphaTreeListDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 SendDlgItemMessage(IDC_BUTTON1,WM_PARENTNOTIFY,WM_USER+1); SendDlgItemMessage(IDC_STATIC1,WM_PARENTNOTIFY,WM_USER+1); SendDlgItemMessage(IDC_TREE1,WM_PARENTNOTIFY,WM_USER+1); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
3、增加成员:
class CMyTreeCtrl : public CTreeCtrl { DECLARE_DYNAMIC(CMyTreeCtrl) public: CMyTreeCtrl(); virtual ~CMyTreeCtrl(); protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnPaint(); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); afx_msg void OnParentNotify(UINT message, LPARAM lParam); afx_msg void OnTvnItemChanging(NMHDR *pNMHDR, LRESULT *pResult); afx_msg void OnTvnItemexpanded(NMHDR *pNMHDR, LRESULT *pResult); afx_msg void OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult); int m_nLeftMargin; RECT m_rcWindow; RECT m_rcClient; afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult); int m_nItemTextMargin; };
4、新建一个类CMyListCtrl,实现WM_PAINT消息
void CMyTreeCtrl::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CTreeCtrl::OnPaint() CDC dcMem; CClientDC dcParent(GetParent()); dcMem.CreateCompatibleDC(&dcParent); dcMem.SelectObject(theBmp); dc.SelectObject(GetStockObject(HOLLOW_BRUSH)); dc.SelectObject(theFont); dc.SetBkColor(CLR_NONE); dc.SetBkMode(TRANSPARENT); CRgn rgn; rgn.CreateRectRgnIndirect(&m_rcClient); dc.SelectClipRgn(&rgn); dc.BitBlt(0,0,m_rcClient.right,m_rcClient.bottom,&dcMem,m_rcWindow.left,m_rcWindow.top,SRCCOPY); HTREEITEM hItem=GetFirstVisibleItem(); HTREEITEM hItemTmp=hItem; RECT rcItemText; CString strItem; do { if (!hItem) { break; } hItemTmp=hItem; GetItemRect(hItem,&rcItemText,FALSE); strItem=GetItemText(hItem); rcItemText.left+=m_nItemTextMargin; rcItemText.right+=m_nItemTextMargin; while (hItemTmp=GetParentItem(hItemTmp)) { rcItemText.left+=GetIndent(); rcItemText.right+=GetIndent(); } rcItemText.left-=m_nLeftMargin; rcItemText.right-=m_nLeftMargin; dc.DrawText(strItem,&rcItemText,DT_LEFT|DT_SINGLELINE|DT_VCENTER); } while(hItem=GetNextVisibleItem(hItem)); }
5、实现TVN_SELCHANGED消息:
void CMyTreeCtrl::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 Invalidate(FALSE); CString strSelPath=L""; strSelPath=GetItemText(GetSelectedItem()); HTREEITEM hItem=pNMTreeView->itemNew.hItem; while (hItem=GetParentItem(hItem)) { strSelPath.Insert(0,L"\\"); strSelPath.Insert(0,GetItemText(hItem)); } LPTSTR lp=(LPTSTR)calloc(MAX_PATH,sizeof(TCHAR)); lstrcpy(lp,strSelPath.GetBuffer()); if (!ItemHasChildren(pNMTreeView->itemNew.hItem)) { strSelPath+=L"\\*.*"; CFileFind ff; CString strFileName=L""; BOOL bFind=ff.FindFile(strSelPath); do { bFind=ff.FindNextFile(); if (ff.IsDots()) { continue; } strFileName=ff.GetFileName(); if (strFileName.IsEmpty()) { break; } if (ff.IsDirectory()) { InsertItem(strFileName,pNMTreeView->itemNew.hItem); } } while (bFind); Expand(pNMTreeView->itemNew.hItem,TVE_EXPAND); Invalidate(FALSE); } *pResult = 0; }
6、实现WM_PARENTNOTIFY消息:
本代码暂不处理浏览文件信处息之后文件增删以及文件重命名等问题。
void CMyTreeCtrl::OnParentNotify(UINT message, LPARAM lParam) { if (message==WM_USER+1&&lParam==0) { DWORD dwDriveFlag=GetLogicalDrives(); int i=0,nMask=0; LPTSTR lp=(LPTSTR)malloc(32); for (i=0;i<32;i++) { nMask=(int)pow(2.0,i); if (nMask&dwDriveFlag) { memset(lp,0,32); wsprintf(lp,L"%C:",65+i); InsertItem(lp); } } GetClientRect(&m_rcClient); GetWindowRect(&m_rcWindow); GetParent()->ScreenToClient(&m_rcWindow); m_nItemTextMargin=GetIndent(); } else { CTreeCtrl::OnParentNotify(message, lParam); } // TODO: 在此处添加消息处理程序代码 }
7、实现WM_HSCROLL、WM_VSCROLL、WM_MOUSEWHEEL、TVN_ITEMCHANGING、TVN_ITEMEXPANDED等消息,代码样板如下:
void CMyTreeCtrl::OnTvnItemChanging(NMHDR *pNMHDR, LRESULT *pResult) { NMTVITEMCHANGE *pNMTVItemChange = reinterpret_cast<NMTVITEMCHANGE *>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; } void CMyTreeCtrl::OnTvnItemexpanded(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 Invalidate(FALSE); *pResult = 0; }
在处理鼠标、键盘消息时注意调用Invalidate(FALSE)。至此,一个透明的树形控件出现在您的眼前了。