When would you need this class:
You might be interested in a tree control which populates it’s
data in a separate thread. This is usually required if you have some fixed data to be
shown in tree view, but it takes a while to populate. The following class would be quite
useful if you have such a requirement. At the moment I have kept the implementation quite
simple, but one can add/modify it according to requirement.
When can you use this class:
- You have some fixed data to be populated in the tree. You can
always do modifications later but the thread works only on some fixed data available. - Given a parent item, you can always supply all it’s children.
How does it work:
I have made this a template class, so that you can associate
your own data as necessary. It takes a structure you define as a parameter. The structure
should contain information required for tree population. Each instance of this structure
would represent one tree node. The class should be in the base class list of your
CtreeView derived class. I name it CtreeViewExt. So your class declaration would
look like this.
class CMyTreeView : public CTreeView, public CtreeViewExt<T> { //...
};
The T parameter would be the structure you define. Please note that the structure should be STL list container
compliant.
The class CtreeViewExt has
a member function which starts off a new thread to collect and populate data. You would
call this member function inside your OnInitialUpdate(). It then asks you to
provide data through two pure virtual member functions , GetRootItems() and GetChildItems(),
which you must override. You need to override one more pure virtual function, the familiar
GetTreeCtrl(), which just returns CtreeView::GetTreeCtrl().
The class will periodically send
a user defined message, WM_DATAAVAILABLE, to your tree view class for which you should
have a message map as follows:
ON_MESSAGE(WM_DATAAVAILABLE, OnDataAvailable)
The message map function would just call the CtreeViewExt::OnDataAvailable() which populates the control.
How to use CtreeViewExt:
Step 1: Define a data structure, say MYDATA, which is STL list<> class compliant and
which represents data specific to tree items.
Step 2: Add CtreeViewExt to the base class list of your
CtreeView based class as follows:
class CMyTreeView : public CTreeView, public CtreeViewExt<T> { //...
};
Step 3: Add messagemap entry for WM_DATAAVAILABLE in your derived class as follows:
// inside header fil afx_msg LONG OnDataAvailable(WPARAM wParam, LPARAM lParam); // Inside implementaion fil BEGIN_MESSAGE_MAP(CMyTreeView, CTreeView) //... ON_MESSAGE(WM_DATAAVAILABLE, OnDataAvailable) END_MESSAGE_MAP() LONG CMyTreeView::OnDataAvailable(WPARAM wParam, LPARAM lParam) { return CTreeViewExt< MYDATA >::OnDataAvailable(wParam, lParam); }
Step 4:Override GetTreeCtrl() as follows:
CTreeCtrl& GetTreeCtrl() const { return CTreeView::GetTreeCtrl(); }
Step 5: Override pure virtual functions GetRootItems() and GetRootItems()
specific to your application.
Step 6: Call CtreeViewExt< MYDATA> ::OnIntialUpdate()in your derived
class as follows:
void CMyTreeView::OnInitialUpdate() { CTreeView::OnInitialUpdate();
CTreeViewExt<MYDATA>::OnInitialUpdate(); }
That’s it!
The class declaration is as follows:
#if !defined(AFX_BASETREEVIEW_H__FA327061_63AC_11D2_89CB_D1CE14573F5F__INCLUDED_) #define AFX_BASETREEVIEW_H__FA327061_63AC_11D2_89CB_D1CE14573F5F__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 100 // BaseTreeView.h : header fil / #includeusing namespace std; //////////////////////////////////////////////////////////////////////////// // CTreeViewExt vie #define WM_DATAAVAILABLE WM_USER+101 // type T specifies any used defined structure specific to the tree dat template<class T> class CTreeViewExt { protected: virtual ~CTreeViewExt() {} struct TreeData { public: unsigned short m_nImage; // Image index in case you provide image // for tree item CString m_strText; // Text for the ite T m_Data; // Data HTREEITEM m_hHandle; // This sometimes refers to handle of // the tree item of this object and // otherwise to the paren public: TreeData() : m_nImage(-1), m_hHandle(NULL) { } bool operator==(const TreeData& Data) { return m_Data == Data.m_Data; } }; protected: list
m_ItemList; public: // OnInitialUpdate starts a new thread with this functio static UINT InitialThreadProc(LPVOID pData) { ASSERT(pData!=NULL); CTreeViewExt* pThis = static_cast (pData); ASSERT(pThis!=NULL); return pThis->ThreadProc(); } // The real thread functio UINT ThreadProc() { // remember to call CoInitialize() here if you are calling COM function GetRootItems(m_ItemList); GetTreeCtrl().SendMessage(WM_DATAAVAILABLE,0,0); list ::iterator it, itTemp, itEnd, itInner; // here we start adding entries to the list in a loop and periodicall // sending message to out control to populate the dat // list intially has entries only for the root items and then it grow // as GetChildItem() returns more entrie itEnd = m_ItemList.end(); itEnd--; for(it = m_ItemList.begin(); it!=m_ItemList.end(); ) { list List; GetChildItems(it,List); //adjust paren for(itInner = List.begin(); itInner!=List.end(); ++itInner) itInner->m_hHandle = it->m_hHandle; // append at the end of the lis m_ItemList.insert(m_ItemList.end(),List.begin(),List.end()); itTemp = it; ++it; if(itTemp==itEnd) { m_ItemList.erase(itTemp); GetTreeCtrl().SendMessage(WM_DATAAVAILABLE,0,0); itEnd = m_ItemList.end(); itEnd--; } else { m_ItemList.erase(itTemp); } } return 1; } virtual void GetRootItems(list & List) = 0; virtual void GetChildItems(list ::iterator it, list & List) = 0; virtual CTreeCtrl& GetTreeCtrl() const = 0; // just populate the tree. You can modify this function as you see fit to you // application. Note that this function gets called in the main threa LONG OnDataAvailable(WPARAM wParam, LPARAM lParam) { list ::iterator it; HTREEITEM hItem; TV_ITEM tvI; TV_INSERTSTRUCT tvIns; HTREEITEM hParent = NULL, hPrev = NULL; bool bFirst = true; for(it = m_ItemList.begin(); it!=m_ItemList.end();++it) { hParent = it->m_hHandle; if(bFirst) { hPrev = hParent; bFirst = false; } tvI.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE| TVIF_CHILDREN; tvI.pszText = (LPSTR)(LPCTSTR)it->m_strText; tvI.cchTextMax = it->m_strText.GetLength(); tvI.iImage = it->m_nImage; tvI.iSelectedImage = it->m_nImage; tvIns.item = tvI; tvIns.hInsertAfter = TVI_SORT; tvIns.hParent = it->m_hHandle; tvIns.item.cChildren = 1 ; hItem = GetTreeCtrl().InsertItem(&tvIns); if(hParent!=hPrev) { GetTreeCtrl().Expand(hPrev,TVE_EXPAND); hPrev = hParent; } else { //hPrev = hParent } it->m_hHandle = hItem; } if(hPrev) GetTreeCtrl().Expand(hPrev,TVE_EXPAND); return 1; } // Attribute public: // Operation public: void OnInitialUpdate() { AfxBeginThread(InitialThreadProc, (LPVOID)this,THREAD_PRIORITY_LOWEST); } // Implementatio protected: }; //////////////////////////////////////////////////////////////////////////// // CTreeViewEx //{{AFX_INSERT_LOCATION} // Microsoft Visual C++ will insert additional declarations immediately before the previous line #endif // !defined(AFX_BASETREEVIEW_H__FA327061_63AC_11D2_89CB_D1CE14573F5F__INCLUDED_
Download demo project – [28.9] KB