due to layout customization needs, I extended CTreeCtrl class.
I absolutely need to use CDC::DrawText() function to dinamically (re)write the text of the single nodes, WITHOUT calling SetItemText() function more than once(mandatory requisite).
Then, I wrote my own implementation of OnPaint() method. I implemented also a DrawItems() method which draws nodes in CTreeCtrl.
Since I don't want to modify anything else than single labels beside the single nodes, then I need to re-implement most of original CTreeCtrl::OnPaint() code.
I only have two doubts:
Simply, currently selected nodes should be appear highlighted.
Some pieces of simplified, auto-explanatory code below:
void MyDlg::OnPaint()
{
CPaintDC dc(this);
CDC dc_ff;
CBitmap bm_ff;
CBitmap *bm_old;
CFont *font;
CFont *old_font;
CFont fontDC;
int old_mode;
GetClientRect(&m_Rect);
dc_ff.CreateCompatibleDC( &dc );
bm_ff.CreateCompatibleBitmap( &dc, m_Rect.Width(), m_Rect.Height() );
dc_ff.SelectObject( &bm_ff );
font = GetFont();
old_font = dc_ff.SelectObject( font );
// Could / Should be called here?
CWnd::DefWindowProc(WM_PAINT, (WPARAM)dc.m_hDC, 0);
old_mode = dc_ff.SetBkMode(TRANSPARENT);
dc_ff.FillSolidRect(m_Rect, dc_ff.GetBkColor());
DrawItems( &dc_ff ); // DrawItems() member function draws single nodes of CTreeCtrl
dc.BitBlt( m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height(), &dc_ff, 0, 0, SRCCOPY);
dc_ff.SelectObject( old_font );
dc_ff.SetBkMode( old_mode );
dc_ff.SelectObject( bm_old );
}
void MyDlg::DrawItems( CDC *pDC )
{
// draw items
HTREEITEM show_item, parent;
CRect rc_item;
CString name;
DWORD tree_style;
int count = 0;
int state;
bool selected;
bool has_children;
show_item = GetFirstVisibleItem();
if ( show_item == NULL )
return;
color = pDC->GetTextColor();
tree_style = ::GetWindowLong( m_hWnd, GWL_STYLE );
do
{
state = GetItemState( show_item, TVIF_STATE );
parent = GetParentItem( show_item );
has_children = ItemHasChildren( show_item ) || parent == NULL;
selected = (state & TVIS_SELECTED) && ((this == GetFocus()) ||
(tree_style & TVS_SHOWSELALWAYS));
if ( GetItemRect( show_item, rc_item, TRUE ) )
{
if ( has_children || selected )
{
if ( selected )
{
// HERE i need to
}
else
// do some stuff...
if ( has_children )
{
HICON icon;
// HERE I need to load CTreeCtrl nodes _DEFAULT_icon
icon = LoadIcon(NULL, IDI_ASTERISK);
if ( icon != NULL )
DrawIconEx( pDC->m_hDC, rc_item.left - 18, rc_item.top, icon, 16, 16,0,0, DI_NORMAL );
}
}
if ( !has_children )
{
HICON icon;
*// HERE I need to load CTreeCtrl nodes _DEFAULT_icon*
icon = LoadIcon(NULL, IDI_ASTERISK);
if ( icon != NULL )
DrawIconEx( pDC->m_hDC, rc_item.left - 18, rc_item.top, icon, 16, 16,0,0, DI_NORMAL );
}
name = GetItemText( show_item );
// ...
if ( selected )
{
pDC->DrawText( "Temp", rc_item, DT_LEFT );
}
else
{
pDC->DrawText( "Temp", rc_item, DT_LEFT );
}
//if ( state & TVIS_BOLD )
// pDC->SelectObject( font );
}
} while ( (show_item = GetNextVisibleItem( show_item )) != NULL );
}
All I need, is source code of an almost-standard CTreeCtrl::OnPaint() implementation. Any suggestion/help is appreciated. :-)
Thanks
IT.
You don't need to overload onPaint. If you set a tree items text as LPSTR_TEXTCALLBACK, the CtreeCtrl will fire the message TVN_GETDISPINFO to retrieve new text every time that item is displayed. Regeister a message handler using ON_NOTIFY if it's in a parent window or ON_NOTIFY_REFLECT if you are subclassing CTreeCtrl. This message handler can assign the text you want but allow the treeCtrl to continue drawing as normal.
If you went the parent Cwnd route, youd need
So you'd need to assign the message handler in the cpp file:
BEGIN_MESSAGE_MAP(MyCWnd, CWnd)
ON_NOTIFY(TVN_GETDISPINFO, tree_ctl_id, CustomTreeControl::OnGetdispinfo) END_MESSAGE_MAP()
Function prototype in header
afx_msg void OnGetdispinfo( NMHDR* pNMHDR, LRESULT* pResult );
This at the end of your class definition
DECLARE_MESSAGE_MAP()
And the actual function to handle the request
void ColumnTreeControl::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) { NMTVDISPINFO * pDispInfo = (NMTVDISPINFO )pNMHDR; TVITEM item = &pDispInfo->item;
if(item->mask & TVIF_TEXT )
{
item->pszText " YOUR CODE HERE";
}
*pResult = 0;
}