How to iterate through all parent nodes of treeview control in c++? - c++

I am new to C++. Is there any way to iterate through all parent nodes starting from the tree ?
Ex :
ParentNode1->Child1
->Child2
ParentNode2->Child1
->Child2
I want to iterate from ParentNode1 to ParentNode2.
Kindly suggest.

Use the following functions to traverse the MFC CTreeCtrl:
void TraverseTree(CTreeCtrl* pTreeCtrl)
{
TraverseTreeBranch(pTreeCtrl, pTreeCtrl->GetRootItem(), TVI_ROOT);
}
void TraverseTreeBranch(CTreeCtrl* pTreeCtrl, HTREEITEM hItem, HTREEITEM hParentItem)
{
// Do stuff with hItem here
HTREEITEM hItemTmp = pTreeCtrl->GetChildItem(hItem);
while(hItemTmp != NULL)
{
TraverseTreeBranch(pTreeCtrl, hItemTmp, hNewItem);
hItemTmp = GetNextSiblingItem(hItemTmp);
}
}

The CTreeView class wraps a CTreeCtrl object. The latter provides CTreeCtrl::GetNextSiblingItem/CTreeCtrl::GetPrevSiblingItem. Those members return the next/previous treeview item, that's on the same hierarchy level.
If you are looking for a Windows API solution, use the TreeView_GetNextSibling/TreeView_GetPrevSibling macros instead, or send a TVM_GETNEXTITEM message.

Related

Unsorting a sorted TreeView list in win32/winapi

this is the sorting code. When the user toggles the sort button this runs and sorts the TreeView
void TreeView::sort(HTREEITEM hTreeItem, bool isRecusive)
{
::SendMessage(_hSelf, TVM_SORTCHILDREN, TRUE, reinterpret_cast<LPARAM>(hTreeItem));
if (!isRecusive)
return;
for (HTREEITEM hItem = getChildFrom(hTreeItem); hItem != NULL; hItem = getNextSibling(hItem))
sort(hItem, isRecusive);
}
win32 already provides a TVM_SORTCHILDREN message to sort a TreeView. I want to unsort the treeview list to the previous state, when the user toggles the sort button from an on state to an off state.
One way to solve this; is to store the treestate before sorting the treeview. Can someone guide me on how to implement this?

First Visible Row in Codenameone

I tried this code to get the first visible row in a scrolling Table inside a BorderLayout.CENTER, but it didn't work, seems the points returned do not reflect the visible cells, unless I am missing a sort of calculation,
thank you for your insights,
#Override
protected void onScrollY(int scrollY) {
super.onScrollY(scrollY); //To change body of generated methods, choose Tools | Templates.
Component c=getComponentAt(50, scrollY);
if (c instanceof Table){
System.err.println("table "+getWidth()+" "+getHeight()+" s "+scrollY);
return;
}
Button b=(Button) c;
System.err.println("c: "+b.getText());
}
getComponentAt(x,y) takes absolute (screen) coordinates. The scrollY value is a relative coordinate in that container.
So what you want is something like:
Component c = getComponentAt(getAbsoluteX()+50, getAbsoluteY() + scrollY)
Also worth nothing that getComponentAt(x,y) will only return components that are focusable or have been set to grab pointer events. If you just want to find the first paintable immediate child of this container, and you're using a BoxLayout.Y_AXIS layout, then you might be better to just iterate through the children until you find one where y is at least the scrollY.
e.g.
Component c = null;
for (Component child : this) {
if (child.getY() + child.getHeight() > scrollY) {
c = child;
break;
}
}
....

How to persist document tab order when using EnableMDITabbedGroups in C++ MFC

VS2010 with an MDI document layout using tabs along the top to switch between documents. Each document is a "live" view into a database, where the persistent data per document is a group of configuration settings.
We would like to allow the user to rearrange the tabs (this functionality is built in), but need to persist this new order. Right now it appears the document z-order is not affected by moving the tabs around. when closing the app, the documents close in the order they were opened so this is not helpful in determining the final tab order on close.
We are using the EnableMDITabbedGroups(TRUE, mdiTabParams) with m_bEnableTabSwap = TRUE which is the default.
Thanks! Ended up with the following solution in the MainFrame::OnClose() method.
Note that this code example uses two custom classes of 1) CSpectraAnalysisUtilityView which inherits from CView and 2) CReviewDataFolder which is our object that we needed to update the recent Tab Order.
This code solution also implements the GetMDITabGroups in case there are multiple group windows open.
void CMainFrame::OnClose()
{
iReviewDataFolderOrder = 1;
const CObList& tabGroups =m_wndClientArea.GetMDITabGroups();
if (0 < tabGroups.GetCount())
{
POSITION pos = tabGroups.GetHeadPosition();
CMFCTabCtrl* pCrtTabCtrl;
while(pos != NULL)
{
pCrtTabCtrl=DYNAMIC_DOWNCAST(CMFCTabCtrl, tabGroups.GetNext(pos));
int count = pCrtTabCtrl->GetTabsNum();
for(int i = 0; i < count; i++)
{
CWnd* pWnd = pCrtTabCtrl->GetTabWndNoWrapper(i);
CMDIChildWnd *pChild = ((CMDIChildWnd*)(pWnd));
if (pChild)
{
CView *pView = pChild->GetActiveView();
if (pView)
{
if (pView->IsKindOf(RUNTIME_CLASS(CSpectraAnalysisUtilityView)))
{
CSpectraAnalysisUtilityView* specUtilView;
specUtilView = (CSpectraAnalysisUtilityView*)pView;
CReviewDataFolder* pDataFolder = specUtilView->GetSpecReviewDataFolder();
if(pDataFolder)
{
pDataFolder->SetRecentOrder(iReviewDataFolderOrder);
iReviewDataFolderOrder++;
}
}
}
}
}
}
}
CMDIFrameWnd::OnClose();
}
Upon destruction of the outer main frame (OnDestroy) you can access the the CMFCTabCtrl members and can loop over each tab and determine the current sequence stored in the tab. GetTabWnd will allow you to access each tab by its index.
To access the tab control use CMDIClientAreaWnd::GetMDITab.

How can i find treeview node by which label equals string variable?

I would like to start by saying thanks to everyone who takes some time to view this thread and try to help.
I have searched the Internet, and couldn't find an example of selecting tree view node that has label text as same as text of a string variable.
On MSDN I have found message TVM_GETISEARCHSTRING but I don't know if it can be used to solve my problem. Even if it can, I still don't know how to use it.
I have a string variable that holds text from database.
When program loads, tree view should have a node with the same text selected.
Please help with some instructions or code snippets, since I have no clue how to even start coding this.
I work in MS Visual Studio Express 2008, on Windows XP, in C++, using pure WIN32 API.
That would be all, again I thank everyone who tries to help.Thank you very very much!
EDIT:
Both answers are good for me, but I don't know how to mark them both, it seems that on this site only one answer can be accepted.
I couldn't have just neglected all the work both of them invested to help me, so I write this in order to try to repay to the Jonathan at least by officially stating that his solution is acceptable for me too, it is just that Tim's solution suits my coding style better.I will also upvote both answers.
The treeview control does not provide an API to search for a label. You will have to manually traverse the items and compare them to your string.
If your treeview is more than one level deep you will have to decide how to traverse the items (either depth first or breadth first). In case there are multiple items with the same label these strategies may return different items.
An implementation might look something like this:
// Helper function to return the label of a treeview item
std::wstring GetItemText( HWND hwndTV, HTREEITEM htItem )
{
static const size_t maxLen = 128;
WCHAR buffer[ maxLen + 1 ];
TVITEMW tvi = { 0 };
tvi.hItem = htItem; // Treeview item to query
tvi.mask = TVIF_TEXT; // Request text only
tvi.cchTextMax = maxLen;
tvi.pszText = &buffer[ 0 ];
if ( TreeView_GetItem( hwndTV, &tvi ) )
{
return std::wstring( tvi.pszText );
}
else
{
return std::wstring();
}
}
This is where the actual traversal takes place. The function is called recursively until no more items can be searched or a match has been found. This implementation uses a case-sensitive comparison (wstring::operator==( const wstring& )). If you need a different predicate you will have to modify the implementation as you see fit.
HTREEITEM FindItemDepthFirstImpl( HWND hwndTV, HTREEITEM htStart, const std::wstring& itemText )
{
HTREEITEM htItemMatch = NULL;
HTREEITEM htItemCurrent = htStart;
// Iterate over items until there are no more items or we found a match
while ( htItemCurrent != NULL && htItemMatch == NULL )
{
if ( GetItemText( hwndTV, htItemCurrent ) == itemText )
{
htItemMatch = htItemCurrent;
}
else
{
// Traverse into child items
htItemMatch = FindItemDepthFirstImpl( hwndTV, TreeView_GetChild( hwndTV, htItemCurrent ), itemText );
}
htItemCurrent = TreeView_GetNextSibling( hwndTV, htItemCurrent );
}
return htItemMatch;
}
The following function wraps the recursion and passes the root element as the starting point. This is the function you would call in your code. It will return an HTREEITEM if one is found, NULL otherwise.
HTREEITEM FindItem( HWND hwndTV, const std::wstring& itemText )
{
HTREEITEM htiRoot = TreeView_GetRoot( hwndTV );
return FindItemDepthFirstImpl( hwndTV, htiRoot, itemText );
}
Unfortunately there is no documented way to search a treeview by item label.
The TVM_GETISEARCHSTRING message returns the search string that the user has typed into the tree (incremental search mode) but it doesn't trigger a search or let you supply your own search string.
The only way to do it is by manually iterating the tree nodes and comparing the labels yourself. Below is an example function, beware that it is recursive and will use about half a KB of stack for every child level.
HTREEITEM TreeView_FindLabel(HWND hWnd, HTREEITEM hItemParent, LPCWSTR pszLabel)
{
TVITEM tvi;
wchar_t wchLabel[256];
for (tvi.hItem = TreeView_GetChild(hWnd, hItemParent); tvi.hItem;
tvi.hItem = TreeView_GetNextSibling(hWnd, tvi.hItem))
{
tvi.mask = TVIF_TEXT | TVIF_CHILDREN;
tvi.pszText = wchLabel;
tvi.cchTextMax = _countof(wchLabel);
if (TreeView_GetItem(hWnd, &tvi))
{
if (_wcsicmp(tvi.pszText, pszLabel) == 0)
return tvi.hItem;
if (tvi.cChildren)
{
HTREEITEM hChildSearch = TreeView_FindLabel(hWnd, tvi.hItem, pszLabel);
if (hChildSearch) return hChildSearch;
}
}
}
return 0;
}
This is not a particularly fast way of searching the tree. If you need to do lots of searches you would be better using a std::map to keep track of the labels and tree items yourself. For example,
std::map<std::wstring, HTREEITEM> mapTreeItems;
// whenever you add an item
HTREEITEM hItem = ListView_InsertItem(...);
mapTreeItems[strLabel] = hItem;
Then you can lookup tree items by label using the map. You just have to remember to update the map and erase labels whenever an item is deleted from the tree.

CTreeCtrl - getting an item position

Is there a way of getting the position (index) of an item in a CTreeCtrl?
I am interested in the index of a node at its particular level.
I was thinking to maintain the item positions within the item "data" field, but the problem is that my tree is sorted and I cannot predict the position an item will receive (well, only if I sort the items in advance which I would like to avoid).
I don't think you can. I assumed that maybe the control could be treated as an array (maybe it still can but I can't find a reference).
Anyways, there are no member functions (according to the MFC API) that give you access to that information
/// there is another way if you "Use Unicode Character Set" (visual studio)
/// Properties->General->Character Set
CPoint point;
GetCursorPos(&point);
m_Tree.ScreenToClient(&point);
UINT nHitFlags;
HTREEITEM hItem = m_Tree.HitTest(point, &nHitFlags);
int idx = m_Tree.MapItemToAccId(hItem);
Get the node handle and then iterate over the elem
Iterate over all the elements, while you count the elements, till you reach the right item?
int GetIndex(const CString & a_Cstr)
{
int idx = 0;
std::vector<CString>::const_iterator _begIt = m_RulesVec.begin();
std::vector<CString>::const_iterator _PosIt = find(m_RulesVec.begin(), m_RulesVec.end(), a_Cstr);
if (_PosIt == m_RulesVec.end()) {
return -1;
}
else {
while (_begIt != _PosIt) {
++idx;
++_begIt;
}
return idx;
}
}
/// it can(must) be done in this function
/// OnNMClickRulesTree(NMHDR *pNMHDR, LRESULT *pResult)
// Create vector like this
std::vector<CString> Vec{"first", "second", "third" };
// OnInit insert items to CtreeCtrl like this
m_Tree.InsertItem("first", hItem);
m_Tree.InsertItem("second", hItem);
m_Tree.InsertItem("third", hItem);
// then get cur selected item like this
CPoint point;
GetCursorPos(&point);
m_Tree.ScreenToClient(&point);
UINT nHitFlags;
HTREEITEM hItem = m_Tree.HitTest(point, &nHitFlags);
// get item text
CString Cstr = m_Tree.GetItemText(hKid);
int idx = GetIndex(Cstr);