Свернуть все узлы в дереве, кроме последнего развернутого

ВВЕДЕНИЕ И СООТВЕТСТВУЮЩАЯ ИНФОРМАЦИЯ:

Мне нужно реализовать следующий сценарий:

  1. Пользователь расширяет узел, например Node 1;

  2. Пользователь расширяет другой узел, например Node 2;

  3. Свернуть предыдущий узел ( Node 1 );

Чтобы визуально объяснить, что я имею в виду, мы будем использовать следующий пример изображения:

введите описание изображения здесь

Теперь, когда пользователь нажимает на Assembly 1 узел или его дочерний узел ComponentsМне нужно свернуть все остальные узлы. Пример изображения ниже иллюстрирует это:

введите описание изображения здесь

МОИ УСИЛИЯ ПО РЕАЛИЗАЦИИ ЭТОГО ПОВЕДЕНИЯ:

Просматривая Интернет и, немного подумав о себе, я смог написать вспомогательную функцию, которая сворачивает узел и его дочерние элементы:

void CollapseNode( HWND hTree, HTREEITEM hti )
{
if( TreeView_GetChild( hTree, hti ) != NULL )
{
TreeView_Expand( hTree, hti, TVE_COLLAPSE );
hti = TreeView_GetChild( hTree, hti );
do
{
CollapseNode( hTree, hti );
}
while( ( hti = TreeView_GetNextSibling( hTree, hti ) ) != NULL  );
}
}

Читая через MSDN документацию я нашел TVN_ITEMEXPANDING а также TVN_ITEMEXPANDED сообщения, которые могут быть полезны.

Я также нашел NM_CLICK уведомление, которое кажется интересным, так как я могу использовать TVM_HITTEST сообщение для проверки, был ли клик +/ — кнопка.

Также я нашел TVN_KEYDOWN сообщение, которое поможет мне с расширением, когда пользователь нажимает стрелка влево или же правая стрелка ключи.

ПРОБЛЕМА:

Я не могу придумать алгоритм использования вышеуказанных сообщений для решения моей задачи.

ВОПРОС:

Можете ли вы предложить мне алгоритм для обработки вышеуказанных сообщений, чтобы я мог позвонить CollapseNode(..) функция?

Что-то вроде этого:

Хиттест в NM_CLICK а затем вызвать вашу функцию или же Сохраните последний развернутый элемент в переменной и сверните его в ответ на TVN_ITEMEXPANDED было бы хорошо для начала.

Спасибо.

1

Решение

Не совсем уверен, что это то, что вы после. Из замечаний, сделанных в комментариях, я думаю, что спецификации диктуют, что и фоны, и сборки должны быть в состоянии оставаться открытыми одновременно, хотя вопрос, по-видимому, указывает на то, что это должна быть или / или ситуация.

В любом случае, посмотрите на это.

По сути, когда я определяю, что узел расширен, я нахожу его предка, который является дочерним по отношению к корневому узлу. Если это корневой узел или один из его дочерних узлов, я ничего не делаю. В противном случае, я звоню вашему CollapseNode функция на всех братьев и сестер расширенного узла.

(Я понимаю, что в моих комментариях что-то не так. Я был бы рад уточнить при необходимости)

Я, вероятно, также должен обратить ваше внимание на другое поведение, наблюдаемое при закрытии узла с расширенными дочерними объектами VS вручную, вызывающего CollapseNode на узле с расширенными дочерними элементами.

Наконец, вам придется проверить и при необходимости изменить контрольный идентификатор (IDC_TREEVIEW1) дерева в onNotify функция.

HTREEITEM getTopLevelParent(HWND treeWnd, TV_ITEM curItem)
{
HTREEITEM treeRoot, tmpItem;
treeRoot = TreeView_GetRoot(treeWnd);

tmpItem = curItem.hItem;
if (tmpItem != treeRoot)
{
while (TreeView_GetParent(treeWnd, tmpItem) != treeRoot)
{
tmpItem = TreeView_GetParent(treeWnd, tmpItem);
}
/*
TV_ITEM topLevelParent;
wchar_t itemText[100];
topLevelParent.hItem = tmpItem;
topLevelParent.cchTextMax = 100;
topLevelParent.pszText = itemText;
topLevelParent.mask = TVIF_TEXT;
TreeView_GetItem(treeWnd, &topLevelParent);
wprintf(L"TopLevelParent (rootChild) Text: %s\n", itemText);
*/
return tmpItem;
}
return NULL;
}

void CollapseNode( HWND hTree, HTREEITEM hti )
{
if( TreeView_GetChild( hTree, hti ) != NULL )
{
TreeView_Expand( hTree, hti, TVE_COLLAPSE );
hti = TreeView_GetChild( hTree, hti );
do
{
CollapseNode( hTree, hti );
}
while( ( hti = TreeView_GetNextSibling( hTree, hti ) ) != NULL  );
}
}

void collapseAllChildrenExcept(HWND treeWnd, HTREEITEM parent, HTREEITEM dontClose)
{
HTREEITEM curNode;

curNode = TreeView_GetChild(treeWnd, parent);
if (curNode != NULL)
{
if (curNode != dontClose)
CollapseNode(treeWnd, curNode);

while ((curNode = TreeView_GetNextSibling(treeWnd, curNode)) != NULL)
{
if (curNode != dontClose)
CollapseNode(treeWnd, curNode);
}
}
}void onNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
if (wParam == IDC_TREEVIEW1)
{
LPNMHDR nmHdr = (LPNMHDR) lParam;

if (nmHdr->code == TVN_ITEMEXPANDED)
{
NM_TREEVIEW FAR *pnmtv = (NM_TREEVIEW FAR *) lParam;
if (pnmtv->action == TVE_COLLAPSE)
printf("TVE_COLLAPSE:\n");
else if (pnmtv->action == TVE_EXPAND)
{
printf("TVE_EXPAND: ");

HWND treeWnd = nmHdr->hwndFrom;
TV_ITEM curItem = pnmtv->itemNew;

/*
curItem.mask = TVIF_TEXT;
curItem.cchTextMax = 100;
wchar_t itemText[100];
curItem.pszText = itemText;
TreeView_GetItem(treeWnd, &curItem);
wprintf(L"%s\n", curItem.pszText);
*/

HTREEITEM rootChild = getTopLevelParent(treeWnd, curItem);
if (rootChild != NULL)
{
//                    printf("Need to close other nodes\n");
HTREEITEM parent, dontCloseMe;
parent = TreeView_GetParent(treeWnd, curItem.hItem);
dontCloseMe = curItem.hItem;
collapseAllChildrenExcept(treeWnd, parent, dontCloseMe);
}

//                else
//                    printf("Node requires no action to other nodes.\n");
}
}
}
}//  This function is called by the Windows function DispatchMessage()
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)                  // handle the messages
{
case WM_DESTROY:
PostQuitMessage (0);       // send a WM_QUIT to the message queue
break;

case WM_NOTIFY:
onNotify(hwnd, wParam, lParam);
break;

default:                      // for messages that we don't deal with
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
2

Другие решения