场景
- 在开发界面程序时,
CTreeViewCtrl
(它实际内部封装的就是Win32
的TreeView
控件)一般会用来作为选择某些类型的树形菜单,点击某项的时候,右边能显示某些对应的数据。当这个控件的宽度固定时,有时候每行的文本项可能由于过长从而穿透了整个控件的水平位置, 从而显示效果来看是不好的。这时候希望可以用省略号的样式来省略后边多出的文本,之后鼠标移动到这个文本项时能显示完整的文字,那么这个文本提示,或者说tooltip
如何实现?
说明
CTreeViewCtrl
在WTL
的新版里可以使用它的子类CTreeViewCtrlExT
。CTreeViewCtrlExT
对HTREEITEM
常用操作进行了封装,也可以对返回的CTreeItemT
类进行操作,它提供了很多便利的方法对HTREEITEM
的处理。
CTreeViewCtrlExT<CWindow> treeView_;
- 默认情况下,当创建一个
CTreeViewCtrl
时,默认就会创建一个tooltip
,除非指定样式TVS_NOTOOLTIPS
才不会创建这个子控件。可是就算是默认创建里,这个tooltip
并不会自动显示,还需要进行一些编码。
treeView_.Create(m_hWnd,NULL,L"Tree",WS_VISIBLE | WS_CHILD |
TVS_SHOWSELALWAYS |
TVS_FULLROWSELECT |
TVS_HASLINES |
TVS_LINESATROOT |
TVS_INFOTIP | WS_BORDER|
TVS_HASBUTTONS,0,kMyTreeViewId);
auto tooltip = treeView_.GetToolTips();
assert(tooltip.m_hWnd);
TreeView
创建时如果提供了TVS_INFOTIP
样式,当鼠标移动到文本项的上边时,就会触发一个TVN_GETINFOTIP
通知。通过捕抓这个通知,就可以设置在tooltip
显示的文本。没错,这个样式就是可让tooltip
显示。注意,这个样式不能和TVS_NOTOOLTIPS
使用,只有创建了tooltip
才会有提示气泡。
BEGIN_MSG_MAP_EX(CView)
NOTIFY_HANDLER_EX(kMyTreeViewId,TVN_GETINFOTIP,onInfoTip)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
LRESULT CView::onInfoTip(LPNMHDR pnmh)
{
LPNMTVGETINFOTIP pTip = (LPNMTVGETINFOTIP)pnmh;
CTreeItem item(pTip->hItem,&treeView_);
item.GetText(pTip->pszText, pTip->cchTextMax);
return 0;
}
例子
- 通过
onInfoTip
方法,把HTREEITEM
的文本内容复制到LPNMTVGETINFOTIP
结构的文本字段里,它的长度最长有1024
字节.
View.h
// View.h : interface of the CView class
//
/
#pragma once
#include <utility>
#include <string>
enum
{
kMyStaticId = WM_USER+1,
kMyTreeViewId,
kMyButtonId
};
class CView : public CWindowImpl<CView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg);
BEGIN_MSG_MAP_EX(CView)
MSG_WM_CREATE(OnCreate)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
NOTIFY_HANDLER_EX(kMyTreeViewId,TVN_GETINFOTIP,onInfoTip)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
int OnCreate(LPCREATESTRUCT lpCreateStruct);
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
void UpdateLayout();
void AddMockData();
void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl);
LRESULT onInfoTip(LPNMHDR pnmh);
private:
std::wstring GetControlText(HWND hwnd,wchar_t* buf = NULL);
HTREEITEM AppendItem(HTREEITEM hParentItem,LPWSTR pText,bool hasChildren = false);
CTreeViewCtrlExT<CWindow> treeView_;
CFont font_normal_;
CFont font_bold_;
CBrushHandle brush_white_;
CBrushHandle brush_hollow_;
CBrush brush_red_;
CToolTipCtrl tooltip_;
TCHAR strToolTipText_[MAX_PATH];
public:
};
View.cpp
// View.cpp : implementation of the CView class
//
/
#include "stdafx.h"
#include "resource.h"
#include <utility>
#include <sstream>
#include <assert.h>
#include "View.h"
#include <CommCtrl.h>
#include <string>
#include <regex>
using namespace std;
BOOL CView::PreTranslateMessage(MSG* pMsg)
{
return FALSE;
}
LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
CMemoryDC mdc(dc,dc.m_ps.rcPaint);
CRect rect_client;
GetClientRect(&rect_client);
mdc.FillSolidRect(rect_client,RGB(255,255,255));
//TODO: Add your drawing code here
return 0;
}
static HFONT GetFont(int pixel,bool bold,const wchar_t* font_name)
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT)); // zero out structure
lf.lfHeight = pixel; // request a 8-pixel-height font
if(bold)
{
lf.lfWeight = FW_BOLD;
}
lstrcpy(lf.lfFaceName, font_name); // request a face name "Arial"
HFONT font = ::CreateFontIndirect(&lf);
return font;
}
std::wstring CView::GetControlText(HWND hwnd,wchar_t* buf)
{
auto length = ::GetWindowTextLength(hwnd);
bool bufNull = false;
if(!buf){
buf = new wchar_t[length+1]();
bufNull = true;
}
::GetWindowText(hwnd,buf,length+1);
std::wstring str(buf);
if(bufNull)
delete []buf;
return str;
}
static std::wstring GetProductBinDir()
{
static wchar_t szbuf[MAX_PATH];
GetModuleFileName(NULL,szbuf,MAX_PATH);
PathRemoveFileSpec(szbuf);
int length = lstrlen(szbuf);
szbuf[length] = L'\\';
szbuf[length+1] = 0;
return std::wstring(szbuf);
}
HTREEITEM CView::AppendItem(HTREEITEM hParentItem,LPWSTR pText,bool hasChildren)
{
TVINSERTSTRUCT tvis;
tvis.hParent=hParentItem;
tvis.hInsertAfter=TVI_LAST;
tvis.itemex.mask=TVIF_TEXT|TVIF_PARAM;
if(hasChildren)
tvis.itemex.mask |= TVIF_CHILDREN;
tvis.itemex.pszText=pText;
return treeView_.InsertItem(&tvis);
}
void CView::AddMockData()
{
AppendItem(NULL,L"Tobey");
AppendItem(NULL,L"Level",true);
auto nameItem = AppendItem(NULL,L"Website");
AppendItem(nameItem,L"https://blog.csdn.net/infoworld");
}
int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
font_normal_ = ::GetFont(16,false,L"Arial");
font_bold_ = ::GetFont(16,true,L"Arial");
// `TVS_INFOTIP`样式是必须的,不然无法触发`TVN_GETINFOTIP`消息.
// `TVS_NOTOOLTIPS`样式不能设置,如果设置了,不会创建`tooltip`控件;
// 默认`treeView`控件会创建一个`tooltip`控件.
treeView_.Create(m_hWnd,NULL,L"Tree",WS_VISIBLE | WS_CHILD |
TVS_SHOWSELALWAYS |
TVS_FULLROWSELECT |
TVS_HASLINES |
TVS_LINESATROOT |
TVS_INFOTIP | WS_BORDER|
TVS_HASBUTTONS,0,kMyTreeViewId);
// 会自动创建一个`tooltip`,这里只是一个例子
auto tooltip = treeView_.GetToolTips();
assert(tooltip.m_hWnd);
AddMockData();
brush_hollow_ = AtlGetStockBrush(HOLLOW_BRUSH);
brush_white_ = AtlGetStockBrush(WHITE_BRUSH);
brush_red_.CreateSolidBrush(RGB(255,0,0));
UpdateLayout();
return 0;
}
LRESULT CView::onInfoTip(LPNMHDR pnmh)
{
LPNMTVGETINFOTIP pTip = (LPNMTVGETINFOTIP)pnmh;
CTreeItem item(pTip->hItem,&treeView_);
item.GetText(pTip->pszText, pTip->cchTextMax);
return 0;
}
void CView::OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
{
}
void CView::UpdateLayout()
{
CRect rect;
GetClientRect(&rect);
CClientDC dc(m_hWnd);
dc.SelectFont(font_normal_);
CSize size_control(700,300);
CRect rect_control = CRect(CPoint(20,20),size_control);
treeView_.MoveWindow(rect_control);
}
图1:
下载
https://download.csdn.net/download/infoworld/87448039
参考
-
TVM_SETTOOLTIPS message (Commctrl.h)
-
How to Use Tree-View Infotips
-
Tree View
-
Using Tree-View Controls