Showing posts with label CTreeCtrl. Show all posts
Showing posts with label CTreeCtrl. Show all posts

2020/05/29

[MFC] TreeCtrl 전체 노드 확장하기

	// 전체 Tree 확장
	std::function< void (HTREEITEM) > ldExpand = [&](HTREEITEM hItem)
	{
		if ( m_treeLibrary.ItemHasChildren(hItem) )
		{
			m_treeLibrary.Expand( hItem, TVE_EXPAND );
			HTREEITEM hChild = m_treeLibrary.GetChildItem(hItem);
			if ( hItem != nullptr ) ldExpand(hChild);
		}

		hItem = m_treeLibrary.GetNextSiblingItem(hItem);
		if ( hItem != nullptr ) ldExpand(hItem);
	};

	HTREEITEM hRootItem = m_treeLibrary.GetRootItem();
	ldExpand(hRootItem);

2009/10/10

CTreeCtrl의 각 노드에 사용자 정의 데이터 할당하기

MFC의 CTreeCtrl 의 함수 중 잘 사용하지 않지만 아주 유용한 멤버함수가 있다.



SetItemData(), GetItemData() 가 바로 그것 인데 이들 함수는 트리의 각 노드에 특정 데이트를 할당하거나 조회할 때 사용하는 함수이다.



데이터 형은 DWORD  형으로 32비트 포인터를 담을 수 있다. Visual Studio 2008 에서는 DWORD_PTR 로 변경되어 64비트 포인터를 담을 수 있다. 어떤 버전부터 DWORD_PTR 로 바뀌었는지는 모르겠지만 64비트 프로그래밍을 지원하는 버전에서는 DWORD_PTR 일 것으로 생각된다.



이 함수를 이용하면 트리의 각 노드에 포인터를 담고 있을 수 있어 어떠한 자료든지 쉽게 할당 할 수 있다.

아래 소스는 트리의 각 노드에 데이터를 할당하고 조회하여 사용하는 간단한 예이다.

// 트리 노드에 할당할 데이터 구조체
struct MyItem
{
int a;
float b;
double c;
};

// 트리에 노드를 추가하고 데이터 포인터 할당하기
HTREEITEM hRoot = m_tree.GetRootItem();
for ( int i = 0; i < 3; ++i )
{
CString strID;
strID.Format( "%d", i );
HTREEITEM hItem = m_tree.InsertItem( strID, hRoot );

// 노드에 할당할 데이터 객체 생성
MyItem* pMyItem = new MyItem;
pMyItem->a = i * 2;
pMyItem->b = (float)(i * 2.0f);
pMyItem->c = (double)(i * 2.0);

// 데이터 포인터 할당
m_tree.SetItemData( hItem, (DWORD)pMyItem );

CString strData;
strData.Format( "%p", hItem );

int nColumn = 1;
m_tree.SetItemText( hItem, nColumn++, strData );
}

// 각각의 노드와 노드에 할당되어 있는 데이터 조회하기
HTREEITEM hItem = m_tree.GetRootItem();
while ( hItem )
{
CString strData;

strData = m_tree.GetItemText( hItem, 0 );

// 노드에 할당되어 있는 데이터 포인터 가져오기
MyItem* pMyItem = (MyItem*)m_tree.GetItemData( hItem );
if ( pMyItem )
{
TRACE( "%s => %p (%d, %f, %f) \n"
, strData, hItem
, pMyItem->a, pMyItem->b, pMyItem->c
);
}
else
{
TRACE( "%s => %p \n", strData, hItem );
}

hItem = m_tree.GetNextSiblingItem( hItem );
}


// 조회 결과
0 => 00601CB8 (0, 0.000000, 0.000000)
1 => 00601D18 (2, 2.000000, 2.000000)
2 => 00601D78 (4, 4.000000, 4.000000)





이는 노드에 포인터를 할당하는 것으로 메모리 관리에 신경을 써야 한다. 그렇지 않을 경우에는 아래와 비슷한 메모리 누수 메세지를 보게 된다.

// 객체 삭제를 하지 않을 경우 보게되는 메모리 누수 메세지
Detected memory leaks!
Dumping objects ->
d:\xxx.cpp(134) : {559} normal block at 0x005BA618, 16 bytes long.
Data: < @ @> 04 00 00 00 00 00 80 40 00 00 00 00 00 00 10 40
d:\xxx.cpp(134) : {545} normal block at 0x005BA4F0, 16 bytes long.
Data: < @ @> 02 00 00 00 00 00 00 40 00 00 00 00 00 00 00 40
d:\xxx.cpp(134) : {531} normal block at 0x005BA450, 16 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
<

Original Post : http://neodreamer-dev.tistory.com/334

CTreeCtrl 에 추가된 Item의 핸들(HTREEITEM)은 변하지 않는군...

특정 데이터를 Tree 컨트롤을 이용해 표현해 주고 트리 컨트롤의 조작으로 데이터를 조작해야 하는데 Tree 의 각 노드의 핸들이 고유한 값을 갖고 있는지 테스트 해 보았다.



간단한 트리를 만들고 각각의 노드의 핸들을 출력해 보고 트리를 정렬한 후 핸들을 출력해 보았다.







초기
0 => 00611CB8
0-0 => 00611D18
0-1 => 00611D78
0-2 => 00611DD8
1 => 00611E38
1-0 => 00611E98
1-1 => 00611EF8
1-2 => 00611F58
2 => 00611FB8
2-0 => 00612018
2-1 => 00612078
2-2 => 006120D8
3 => 00612138
3-0 => 00612198
3-1 => 006121F8
3-2 => 00612258
4 => 006122B8
4-0 => 00612318
4-1 => 00612378
4-2 => 006123D8

정렬 후
4 => 006122B8
4-2 => 006123D8
4-1 => 00612378
4-0 => 00612318
3 => 00612138
3-2 => 00612258
3-1 => 006121F8
3-0 => 00612198
2 => 00611FB8
2-2 => 006120D8
2-1 => 00612078
2-0 => 00612018
1 => 00611E38
1-2 => 00611F58
1-1 => 00611EF8
1-0 => 00611E98
0 => 00611CB8
0-2 => 00611DD8
0-1 => 00611D78
0-0 => 00611D18

<

Original Post : http://neodreamer-dev.tistory.com/333

2009/09/30

CTreeCtrl 의 CheckBox 상태 변경 이벤트 작성하기

#define WM_USER_TREE_CHANGE_CHECK        WM_USER + 100

void CTestDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TREE, m_ctrlTree);
}

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
:
ON_NOTIFY(NM_CLICK, IDC_TREE, &CTestDlg::OnNMClickTree)
ON_MESSAGE( WM_USER_TREE_CHANGE_CHECK, &CTestDlg::OnTreeChangeCheck )
:
END_MESSAGE_MAP()

void CTestDlg::OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult)
{
DWORD pos = ::GetMessagePos();
CPoint point( LOWORD( pos ), HIWORD( pos ) );

m_ctrlTree.ScreenToClient( &point );

UINT nFlags = 0;
HTREEITEM hItem = m_ctrlTree.HitTest( point, &nFlags );

if ( hItem )
{
if ( nFlags & TVHT_ONITEMSTATEICON )
{
PostMessage( WM_USER_TREE_CHANGE_CHECK, (WPARAM)pNMHDR->hwndFrom, (LPARAM)hItem );
}
}

*pResult = 0;
}

LRESULT CTestDlg::OnTreeChangeCheck( WPARAM wParam, LPARAM lParam )
{
HTREEITEM hItem = (HTREEITEM)lParam;

HTREEITEM hParent = m_ctrlTree.GetParentItem( hItem );
if ( hParent )
{
BOOL bCheck = m_ctrlTree.GetCheck( hItem );

m_ctrlTree.SetCheck( hParent, bCheck );
}

return 0;
}

Original Post : http://neodreamer-dev.tistory.com/330

CTreeCtrl 탐색하기

별 것 아니지만 안쓰면 자꾸 잊어버린다.


TCHAR szItem[256];

TVITEM tvItem;
tvItem.cchTextMax = 256;
tvItem.pszText = szItem;
tvItem.mask = TVIF_TEXT | TVIF_HANDLE;

HTREEITEM hItem = m_ctrlTree.GetRootItem();

while ( hItem )
{
tvItem.hItem = hItem;
m_ctrlTree.GetItem( &tvItem );

TRACE( _T("%s\n"), tvItem.pszText );

if ( m_ctrlTree.ItemHasChildren( hItem ) )
{
HTREEITEM hSubItem = m_ctrlTree.GetChildItem( hItem );

while ( hSubItem )
{
tvItem.hItem = hSubItem;
m_ctrlTree.GetItem( &tvItem );

TRACE( _T("--- %s\n"), tvItem.pszText );

hSubItem = m_ctrlTree.GetNextSiblingItem( hSubItem );
}
}

hItem = m_ctrlTree.GetNextSiblingItem( hItem );
}


Original Post : http://neodreamer-dev.tistory.com/329