diff --git a/MusicPlayer2/UIElement.cpp b/MusicPlayer2/UIElement.cpp index 54696d00..c10f2501 100644 --- a/MusicPlayer2/UIElement.cpp +++ b/MusicPlayer2/UIElement.cpp @@ -2936,16 +2936,31 @@ std::wstring UiElement::TreeElement::GetItemText(int row, int col) int UiElement::TreeElement::GetRowCount() { - const auto& root_nodes{ GetRootNodes() }; int row_count{}; + IterateDisplayedNodeInOrder([&](const Node*) ->bool { + row_count++; + return false; + }); + return row_count; +} + +void UiElement::TreeElement::QuickSearch(const std::wstring& key_word) +{ + tree_searched = !key_word.empty(); + + tree_search_result.clear(); + if (key_word.empty()) + return; + //遍历所有节点,获取匹配的节点,并添加到tree_search_result中 + const auto& root_nodes{ GetRootNodes() }; for (const auto& root : root_nodes) { - root->IterateNodeInOrder([&](const Node*) ->bool { - row_count++; + root->IterateNodeInOrder([&](const Node* cur_node) ->bool { + if (IsNodeMathcKeyWord(cur_node, key_word)) + tree_search_result.insert(cur_node); return false; - }, true); + }, false); } - return row_count; } int UiElement::TreeElement::GetItemLevel(int row) @@ -3024,23 +3039,17 @@ void UiElement::TreeElement::MouseLeave() int UiElement::TreeElement::GetNodeIndex(const Node* node) { - const auto& root_nodes{ GetRootNodes() }; int i{}; int rtn_index{ -1 }; - for (const auto& root : root_nodes) - { - root->IterateNodeInOrder([&](const Node* cur_node) ->bool { - if (cur_node == node) - { - rtn_index = i; - return true; - } - i++; - return false; - }, true); - if (rtn_index >= 0) - break; - } + IterateDisplayedNodeInOrder([&](const Node* cur_node) ->bool { + if (cur_node == node) + { + rtn_index = i; + return true; + } + i++; + return false; + }); return rtn_index; } @@ -3050,28 +3059,67 @@ UiElement::TreeElement::Node* UiElement::TreeElement::GetNodeByIndex(int index) if (index >= 0) { Node* find_node{}; - auto& root_nodes{ GetRootNodes() }; int i{}; - for (auto& root : root_nodes) - { - root->IterateNodeInOrder([&](Node* cur_node) ->bool { - if (i == index) - { - find_node = cur_node; - return true; - } - i++; - return false; - }, true); - if (find_node != nullptr) - break; - } + IterateDisplayedNodeInOrder([&](Node* cur_node) ->bool { + if (i == index) + { + find_node = cur_node; + return true; + } + i++; + return false; + }); return find_node; } return nullptr; } +bool UiElement::TreeElement::IsNodeMathcKeyWord(const Node* node, const std::wstring& key_word) +{ + //判断节点本身是否匹配 + for (const auto& item : node->texts) + { + const std::wstring& text{ item.second }; + if (!text.empty() && theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, text)) + return true; + } + + //如果节点本身不匹配,则遍历所有子节点,如果有一个子节点匹配,则节点匹配 + for (const auto& child : node->child_list) + { + if (IsNodeMathcKeyWord(child.get(), key_word)) + return true; + } + + return false; +} + +bool UiElement::TreeElement::IsNodeDisplayed(const Node* node) +{ + if (node != nullptr) + { + if (tree_searched) + return tree_search_result.contains(node); + else + return true; + } + return false; +} + +void UiElement::TreeElement::IterateDisplayedNodeInOrder(std::function func) +{ + const auto& root_nodes{ GetRootNodes() }; + for (const auto& root : root_nodes) + { + root->IterateNodeInOrder([&](Node* cur_node) ->bool { + if (IsNodeDisplayed(cur_node)) + return func(cur_node); + return false; + }, true); + } +} + UiElement::TestTree::TestTree() { //创建测试节点 diff --git a/MusicPlayer2/UIElement.h b/MusicPlayer2/UIElement.h index 1c4ca230..2f7521f0 100644 --- a/MusicPlayer2/UIElement.h +++ b/MusicPlayer2/UIElement.h @@ -1,6 +1,7 @@ #pragma once #include "CPlayerUIBase.h" #include "MediaLibHelper.h" +#include class CUiSearchBox; @@ -329,7 +330,7 @@ namespace UiElement virtual bool IsMultipleSelectionEnable() { return false; } //是否允许多选 virtual void OnRowCountChanged(); //当列表行数发生变化时响应此函数 - void QuickSearch(const std::wstring& key_word); //根据关键执行快速搜索(筛选出匹配的项) + virtual void QuickSearch(const std::wstring& key_word); //根据关键执行快速搜索(筛选出匹配的项) virtual bool IsItemMatchKeyWord(int row, const std::wstring& key_word); //判断指定行是否匹配关键字(用于快速搜索功能,默认匹配每一列中的文本,只要有一列的文本匹配就返回true,派生类可重写此函数) int GetDisplayRowCount(); //获取要显示的行数。(处于搜索状态时返回搜索结果数量,正常状态下同GetRowCount) @@ -363,6 +364,7 @@ namespace UiElement int scroll_handle_length_comp{}; //计算滚动条把手长度时的补偿量 std::map hover_buttons; //鼠标指向时的按钮 int last_row_count{}; + private: std::vector search_result; //保存搜索结果的序号 bool searched{}; //是否处于搜索状态 }; @@ -758,14 +760,20 @@ namespace UiElement // 通过 ListElement 继承 std::wstring GetItemText(int row, int col) override; int GetRowCount() override; + //树控件不使用基类ListElement的搜索逻辑 + virtual void QuickSearch(const std::wstring& key_word) override; std::map collapsd_rects; //折叠标志的矩形区域(key是行) int collaps_indicator_hover_row{ -1 }; //鼠标指向的折叠标志的行号 protected: int GetNodeIndex(const Node* node); //查找一个节点的序号(如果节点被折叠或不存在则返回-1) - Node* GetNodeByIndex(int index); //根据一个节点的序号查找节点(忽略被折叠的节点) - + Node* GetNodeByIndex(int index); //根据一个节点的序号查找节点(忽略被折叠的节点) + bool IsNodeMathcKeyWord(const Node* node, const std::wstring& key_word); //判断一个节点是否匹配关键字 + bool IsNodeDisplayed(const Node* node); + void IterateDisplayedNodeInOrder(std::function func); //遍历所有可见的节点 + std::set tree_search_result; //保存搜索结果 + bool tree_searched{}; //是否处于搜索状态 }; class TestTree : public TreeElement