折叠树视图中的所有节点,最后一个扩展节点除外

时间:2014-05-15 04:40:10

标签: c++ winapi collapse treeviewitem

引言及相关资料:

我需要实现以下场景:

  1. 用户展开节点,例如Node 1;

  2. 用户展开另一个节点,例如Node 2;

  3. 折叠上一个节点(Node 1);

  4. 为了直观地解释我的意思,我们将使用以下示例图像:

    enter image description here

    现在,当用户点击Assembly 1节点或其子节点Components时,我需要折叠每个其他节点。下面的示例图片说明了这一点:

    enter image description here

    我努力实现这种行为:

    浏览互联网,稍微考虑一下我自己,我能够编写帮助函数来折叠节点及其子节点:

    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_ITEMEXPANDINGTVN_ITEMEXPANDED条消息。

    我还发现NM_CLICK通知似乎很有趣,因为我可以使用TVM_HITTEST消息来测试点击是否在 +/- 按钮上。

    此外,我发现TVN_KEYDOWN消息可以帮助我在用户按左箭头右箭头键时进行扩展。

    问题:

    我想不出使用上述消息来解决我的任务的算法。

    问题:

    您能否建议我处理上述消息的算法,以便我可以调用CollapseNode(..)函数?

    这样的事情:

    Hittest NM_CLICK然后调用您的函数将最后一个展开的项目存储在变量中并将其折叠以响应TVN_ITEMEXPANDED 好好开始。

    谢谢。

1 个答案:

答案 0 :(得分:2)

不太确定这是你所追求的。根据评论中的评论,我认为规范要求背景和大会应该能够同时保持开放,尽管这个问题似乎表明它应该是一种或两种情况。

无论如何,请看一下。

基本上,当我确定扩展节点时,我发现它的祖先是根节点的子节点。如果它是根节点或根节点的子节点之一,我什么都不做。否则,我会在所有扩展节点的兄弟节点上调用CollapseNode函数。

(我意识到我的评论是呃,有点缺乏。我很乐意根据需要澄清)

我可能还应该引起您的注意,当手动关闭具有扩展子级VS的节点时,观察到的不同行为VS在具有扩展子节点的节点上调用CollapseNode。

最后,您必须根据需要检查并更改IDC_TREEVIEW1函数中树视图的控件ID(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;
}