How can I find a treeview node by which the label is equal to a string variable?

I would like to start by thanking everyone who takes some time to review this topic and try to help.

I searched the Internet and could not find an example of selecting a tree view of a node that has label text just like the text of a string variable.

I found the message TVM_GETISEARCHSTRING on MSDN, but I don’t know if it can be used to solve my problem. Even if it’s possible, I still don’t know how to use it.

I have a string variable containing text from a database. When loading the program, the tree view should have a node with the same selected text.

Please help with some instructions or code snippets since I have no idea how to start coding this.

I work in MS Visual Studio Express 2008, in Windows XP, in C ++, using the pure WIN32 API.

That's all, thanks again to everyone who is trying to help. Thank you very much!

EDIT:

Both answers are good for me, but I don’t know how to label them, it seems that only one answer can be accepted on this site.

I could not just neglect all the work that they both did to help me, so I am writing this to try to repay Jonathan, at least officially declaring that his decision is acceptable to me too. it's just that Tim's solution is better suited to my coding style. I will also support both answers.

+6
source share
2 answers

The treeview control does not provide an API for finding a label. You will have to manually move the elements and compare them with your row.

If your tree-like image is at a depth of more than one level, you will need to decide how to move around the objects (first, first in depth, or in width). If there are multiple items with the same label, these strategies can 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 bypass occurs. The function is called recursively until more items are found or a match is found. This implementation uses a case-sensitive comparison ( wstring::operator==( const wstring& ) ). If you need another predicate, you will have to modify the implementation as you wish.

 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 completes the recursion and passes the root element as a starting point. This is the function you call in your code. It will return HTREEITEM if it is found, NULL otherwise.

 HTREEITEM FindItem( HWND hwndTV, const std::wstring& itemText ) { HTREEITEM htiRoot = TreeView_GetRoot( hwndTV ); return FindItemDepthFirstImpl( hwndTV, htiRoot, itemText ); } 
+6
source

Unfortunately, there is no documentary way to search for a tree structure by element label.

The TVM_GETISEARCHSTRING message returns a search string that the user has entered into the tree (incremental search mode), but does not start the search or does not provide your own search string.

The only way to do this is to manually iterate the tree nodes and compare the labels yourself. The following is an example function, beware that it is recursive and will use approximately half a kilobyte of stack for each 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 to search for a tree. If you need to do a lot of queries, you'd better use std::map to track labels and tree elements yourself. For instance,

 std::map<std::wstring, HTREEITEM> mapTreeItems; // whenever you add an item HTREEITEM hItem = ListView_InsertItem(...); mapTreeItems[strLabel] = hItem; 

Then you can search for tree items by label using the map. You just need to remember to update the map and erase labels whenever an item is removed from the tree.

+6
source

Source: https://habr.com/ru/post/949939/


All Articles