Click here to Skip to main content
Click here to Skip to main content

CPropTree v1.0 - Property Tree Control

By , 1 Jan 2002
 

Sample Image Sample Image Sample Image

Introduction

The CPropTree class implements a tree control that is similar to the property view seen in Visual Studio .Net. The source project compiles to a DLL so you can easily incorporate it into your project. You can check my web page for more information on the control.

The control has two window areas:

  • Tree Control
  • Descriptive area

The tree control section functions just a like a normal tree control with an addition of a splitter bar separating the tree item properties. Tree item properties are inherited from the CPropTreeItem class. These items can be edit controls, static text, dropdown combo list, or any type of control you wish to create. Items on the root level of the tree control do not have editable properties. They are used as section headers.

Tree items can contain checkboxes. By default properties that are editable (non-readonly), are displayed in bold lettering. Read only or non-editable items are displayed in a normal font.

The descriptive area displays the selected item's text and any informational text. This section can be displayed or hidden by calling CPropTree::ShowInfoText().

Implementation

To use the control, create an instance of the class in your dialog or view class header. In the OnInitDialog() or OnCreate() initialize the control:

DWORD dwStyle;
CRect rc;

// PTS_NOTIFY - CPropTree will send notification messages to the parent window
dwStyle = WS_CHILD|WS_VISIBLE|PTS_NOTIFY;

// Init the control's size to cover the entire client area
GetClientRect(rc);

// Create CPropTree control
m_Tree.Create(dwStyle, rc, this, IDC_PROPERTYTREE);

To add items to the control, dynamically create objects inherited by the CPropTreeItem class and call the CPropTree::InsertItem() method.

CPropTreeItem* pItem1;

pItem1 = m_Tree.InsertItem(new CPropTreeItem());
pItem1->SetLabelText(_T("Properties"));
pItem1->SetInfoText(_T("This is a root level item"));

CPropTreeItem* pItem2;

pItem2 = m_Tree.InsertItem(new CPropTreeItemEdit(), pItem1);
pItem2->SetLabelText(_T("EditItem"));
pItem2->SetInfoText(_T("This is a child item of Properties, with an edit control"));

pItem2->SetItemValue((LPARAM)_T("This is some default text for the edit control"));

Advanced Features

Notification Messages

The control uses WM_NOTIFY notification messages to signal events. Add a ON_NOTIFY message handler to the parent window to process notifications. The control supports most of the common NM_ codes with addition of the following CPropTree specific WM_NOTIFY codes.

  • PTN_INSERTITEM when an item is inserted
  • PTN_DELETEITEM when an item is about to be deleted
  • PTN_DELETEALLITEMS when a call is made to delete all items
  • PTN_ITEMCHANGED when an item's property has been modified
  • PTN_SELCHANGE when the current selection changed
  • PTN_ITEMEXPANDING when an item is about to expand or close
  • PTN_COLUMNCLICK when the mouse clicks on the splitter bar
  • PTN_PROPCLICK when the mouse clicks on an item's property area
  • PTN_CHECKCLICK when the mouse clicks on an item's checkbox

PTN_ notification messages returns the NMPROPTREE structure. You can use this structure along with the CPropTreeItem::SetCtrlID() method to determine the tree item that sent an event.

[...]
	//}}AFX_MSG_MAP
	ON_NOTIFY(PTN_ITEMCHANGED, IDC_PROPERTYTREE, OnItemChanged)
END_MESSAGE_MAP()


void CMyDialog::OnItemChanged(NMHDR* pNotifyStruct, LRESULT* plResult)
{
	LPNMPROPTREE pNMPropTree = (LPNMPROPTREE)pNotifyStruct;

	if (pNMPropTree->pItem)
	{
		// retrieve pItem's changed data
	}

	*plResult = 0;
}

Custom Property Items

The library already has some default derived CPropTreeItem classes ready to use. Such as an edit control CPropTreeItemEdit, color picker CPropTreeItemColor, dropdown combobox CPropTreeItemCombo and static text CPropTreeItemStatic. To create your own custom property items:

  • Create your own class inherited by CPropTreeItem. This class usually will have multiple inheritance depending on what type of item you want to create.
    class CMyCustomEditPropItem : public CEdit, public CPropTreeItem
    {
    public:
    	CMyCustomEditPropItem();
    	virtual ~CMyCustomEditPropItem();
    
    	[...]
    };
    
    class CMyCustomComboBoxPropItem : public CComboBox, public CPropTreeItem
    {
    public:
    	CMyCustomComboBoxPropItem();
    	virtual ~CMyCustomComboBoxPropItem();
    
    	[...]
    };
    
  • Override the CPropTreeItem virtual methods to implement your property item.
  • Dynamically create an instance of your class and insert it into a CPropTree control.

The methods most often overriden from CPropTreeItem are:

  • CPropTreeItem::OnActivate(). Called when the property area is clicked by the mouse or the enter key has been pressed on the selected item. The OnActivate() method is where you show the property item's window if it has one (such as an edit control or a popup menu).
  • CPropTreeItem::OnCommit(). Called when data has been commited. In this method you would extract the changed data and hide the property's item's window. OnCommit() gets called when CommitChanges() is called. A derived CPropTreeItem class would call CommitChanges() during a loss of the input focus or if the "Enter" key is press as in a edit control.
  • CPropTreeItem::DrawAttribute(). CPropTree calls DrawAttribute() when the property item needs to be displayed. Drawing is done directly on the display context of the PropTree control.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

sramsay
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionHow can it support VS2008, It can't Draw Text in VS2008.Thanks!membermconstor3 May '10 - 21:55 
Thanks for your PropTree first, I like it!
It seems to have something wrong with "DrawText()...."
Do you have the new version working well in VS2008?
Thank you very much!
AnswerRe: How can it support VS2008, It can't Draw Text in VS2008.Thanks!memberwindsky11030 Mar '11 - 15:51 
//targetver.h
#ifndef WINVER // 指定要求的最低平台是 Windows xp。
#define WINVER 0x0501 // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif
 
#ifndef _WIN32_WINNT // 指定要求的最低平台是 Windows xp。
#define _WIN32_WINNT 0x0501 // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif
 
#ifndef _WIN32_WINDOWS // 指定要求的最低平台是 Windows 98。
#define _WIN32_WINDOWS 0x0410 // 将此值更改为适当的值,以适用于 Windows Me 或更高版本。
#endif
 
#ifndef _WIN32_IE // 指定要求的最低平台是 Internet Explorer 6.0。
#define _WIN32_IE 0x0600 // 将此值更改为相应的值,以适用于 IE 的其他版本。
#endif
I will survive...

GeneralLicensemembersilent_neiep1 Dec '09 - 15:34 
This is a great control.
We try to use it in our product.
But I am not sure the license.
Can we use it free or should we pay for it?
 
Thanks,
Lou.
Generalcolor select dialog bugmemberyq_sun25 Jun '09 - 18:41 
when click color item, pop color select dialog, click "more colors" button, pop pick color dialog. then close it.
click color item again. at this time,click other blank area, color dialog doesn`t disappear.
 
if you click big color palette `s OK button. this problem does`t appear.
 

void CPropTreeItemColor::OnLButtonDown(UINT, CPoint point)
{
if (m_nSpot!=-1)
{
m_cColor = _crColors[m_nSpot].color;
CommitChanges();
}
else
if (m_rcButton.PtInRect(point))
{
CHOOSECOLOR cc;
COLORREF clr[16];
 
ZeroMemory(&cc, sizeof(CHOOSECOLOR));
cc.Flags = CC_FULLOPEN|CC_ANYCOLOR|CC_RGBINIT;
cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = m_hWnd;
cc.rgbResult = m_cColor;
cc.lpCustColors = s_pColors ? s_pColors : clr;
 
memset(clr, 0xff, sizeof(COLORREF) * 16);
clr[0] = m_cColor;
 
m_bInDialog = TRUE;
 
ASSERT(m_pProp!=NULL);
m_pProp->DisableInput();
 
ShowWindow(SW_HIDE);
 
if (ChooseColor(&cc))
m_cColor = cc.rgbResult;
 
m_pProp->DisableInput(FALSE);
CommitChanges();
 
m_bInDialog = FALSE; //add here.
}
}
GeneralFind a bug work with sizecontrolbar [modified]memberm_harriss7 May '09 - 11:10 
It's a good job any way, thanks first!
but a bug is found.
 
When i used it with a sizing control bar, the treelist was not displayed normally. and found that, it was the sake of this function :
 
void CPropTreeList::RecreateBackBuffer(int cx, int cy)
did not work correctly. for sometimes, cx & cy is very big, and m_BackBuffer bitmap can't be created. although the following size changes of the bar comes, but cx and cy are not bigger than the original size, so the buffer bitmap will never be created, and there will be no imagination of properties list can be displayed.
 
Infact, the return value of "CreateBitmap" function should be judged, and recreation job is also needed, till the buffer bitmap is built.
 
Two changes are listed as follow, it will work on a sizing control bar then. Wink | ;)
 
void CPropTreeList::RecreateBackBuffer(int cx, int cy)
{
	if (m_BackBufferSize.cx<cx || m_BackBufferSize.cy<cy)
	{
		m_BackBufferSize = CSize(cx, cy);
 
		CWindowDC dc(NULL);
 
		int nPlanes = dc.GetDeviceCaps(PLANES);
		int nBitCount = dc.GetDeviceCaps(BITSPIXEL);
 
		m_BackBuffer.DeleteObject();
		if(!m_BackBuffer.CreateBitmap(cx, cy, nPlanes, nBitCount, NULL))  //add an IF here
			m_BackBufferSize = CSize(0,0);                            //an additional job
	}
}

 
modified on Thursday, May 7, 2009 5:21 PM

GeneralMemory leaks found and fixed [modified]memberShashidhar Kamath23 Oct '08 - 12:42 
The recursive delete function does not delete any item, it just recursivley call the Delete Item.
 
So when you call DeleteAllitems it does not actually delete the memory for all the items.
 

Here is the modified code
 

 
void CPropTree::Delete(CPropTreeItem* pItem)
{
if (pItem && pItem!=&m_Root && SendNotify(PTN_DELETEITEM, pItem))
return;
 
// passing in a NULL item is the same as calling DeleteAllItems
if (!pItem)
pItem = &m_Root;
 
// delete children
 
CPropTreeItem* pIter;
CPropTreeItem* pNext;
 
pIter = pItem->GetChild();
while (pIter)
{
pNext = pIter->GetSibling();
DeleteItem(pIter);
delete pIter // <------------------------------Added this line to original code
pIter = pNext;
}
 
// unlink from tree
if (pItem->GetParent())
{
if (pItem->GetParent()->GetChild()==pItem)
pItem->GetParent()->SetChild(pItem->GetSibling());
else
{
pIter = pItem->GetParent()->GetChild();
while (pIter->GetSibling() && pIter->GetSibling()!=pItem)
pIter = pIter->GetSibling();
 
if (pIter->GetSibling())
pIter->SetSibling(pItem->GetSibling());
}
}
 
if (pItem!=&m_Root)
{
if (pItem==GetFocusedItem())
SetFocusedItem(NULL);
delete pItem;
}
}
 
 
 
modified on Thursday, October 23, 2008 7:52 PM

GeneralControl on the dialog box with other controlsmemberShashidhar Kamath23 Oct '08 - 8:44 
Hello,
 
I am using the Treelist control on a dialog box with some buttons at the bottom of this control. But for some reason the whole dialog box comes with white background and all my buttons have painting issue.
 
I am just adding some CPropTreeItemEdit items to the control.
 
Any help is greately appreciated.
 
Thanks
Shashi
GeneralCheckbox is on wrong sidememberjohnnyk427728 Jun '08 - 22:23 
Great tool, I'm using it and find it quite lovely, however my one complaint is that checkbox tree items display the checkbox in the left column for some reason. For every other property, the left column is the parameter name, and the right column is the value. Other than that nice work Smile | :)
-John Krajewski
GeneralImplementing tab keymemberIonut Codrut19 Nov '07 - 8:17 
Hello!
How could I implement tab (WS_TABSTOP) for the tree control elements?
I have tried
 
m_Tree.ModifyStyle(0,WS_TABSTOP);
but it doesn't work
 
Any idea?
Ioan
GeneralDebug assertion error [modified]memberIonut Codrut19 Nov '07 - 7:32 
Hello!
I try to use this tree control but in debug Unicode mode at the following line:
 
m_Tree.Create(dwStyle, rc, this, IDC_PROPERTYTREE);
 
I got an assertion error:
 
in the CPropTree::Create(..)
at line:
LPCTSTR pszCreateClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW));
 
PS: in Release mode the code is working fine..
Any idea?
Ioan
 

-- modified at 16:42 Monday 19th November, 2007

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 2 Jan 2002
Article Copyright 2002 by sramsay
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid