树形视图中的分层数据和树形视图更新技术

3
我有很多(分层)数据需要在TreeView中显示(包括子项,可能达到20K个或更多)。我的数据的特殊问题是,在TreeView中显示的每个对象都可以存在于许多TreeView项中。我的意思是,我可能会有像这样的层次结构:
1. Item_A -> Item_B -> ItemC 2. Item_B -> Item_C 3. ItemC
假设Item_A包含像上面显示的Item_B,Item_B包含Item_C。这意味着我的列表也将显示Item_B和Item_C的层次结构。现在考虑发生了某些事情,比如更改了作为Item_B显示的对象的名称。那么当然必须更新这两个项。现在考虑树形视图中有成千上万个带有复杂层次结构的项。你会使用什么策略来更新TreeView?速度当然是主要关注点,但易用性和维护性也很重要。目前,我保持内部映射列表项到对象以及反向映射,以快速查找和更新项目。这是正确的策略吗?通过在每次更新后重新创建列表,我可以丢弃大量代码,但我不知道哪些项目路径已展开或折叠。我该如何解决这个问题?我应该在内部容器中存储展开的路径吗?
谢谢。
PS:编程语言是C++,GUI库是QT3。
4个回答

1

我使用 wxWidgets 树形控件解决了一个类似的问题。我使用了单例引用计数器来跟踪我放入控件中的对象,并使用迭代器来遍历它们。以下是一个示例。

class ReferenceCounter
{
public:
    // Singleton pattern. Implementation left up to you.
    static ReferenceCounter& get();

    void add(const TreeData& data) {
        mCounter[data.getId()].push_back(&data);
    }

    void remove(const TreeData& data) {
        const CounterType::const_iterator itr = mCounter.find(data.getId());
        if (itr != mCounter.end()) {
            ItemType& items = itr->second;
            items.erase(std::remove(items.begin(), items.end(), &data), items.end());
            if (items.empty()) {
                mCounter.erase(itr);
            }
        }
    }

    typedef std::vector<TreeData*> ItemType;
    ItemType::iterator begin(const TreeData& data) {
        const CounterType::const_iterator itr = mCounter.find(data.getId());
        if (itr != mCounter.end()) {
            return itr->second.begin();
        }
        // Else condition handling left up to you.
    }

    ItemType::iterator end(const TreeData& data) {
        const CounterType::const_iterator itr = mCounter.find(data.getId());
        if (itr != mCounter.end()) {
            return itr->second.end();
        }
        // Else condition handling left up to you.
    }

private:     
    typedef std::map<int, ItemType> CounterType;
    CounterType mCounter;
};

class TreeData
{
public:
    TreeData() { ReferenceCounter::get().add(*this); }
    ~TreeData() { ReferenceCounter::get().remove(*this); }

    // Get database rows or whatever your tree is tracking.
    int getId() const;
};

因此,对于任何TreeData,您都可以在引用计数器中查找具有匹配ID的所有其他TreeData。这使得保持名称和其他信息最新变得容易且快速。我们的树可以处理超过1,000,000个节点而不会出现问题。在我的实现中,我将迭代内容封装在boost :: iterator_facade类中,以便更轻松地使用。


1

如果您的项目可以使用Qt4,请使用Qt4模型/视图。

您将不得不编写自己的模型,如果您从未这样做过,可能会很繁琐,但一旦设置好,您就可以轻松地引用/更新同一对象的多个实例。选择/多选也可以处理。

我不是Qt的模型/视图实现的忠实粉丝(因为模型/视图/控制器设计模式相当古老),但它有助于在GUI中组织数据。


1

使用widget->setUpdatesEnabled(false)禁用更新,然后进行所有所需的编辑,最后使用widget->setUpdatesEnabled(true)重新启用。

请参阅Qt文档


1

我很久以前做过类似的事情,使用了Windows TreeView公共控件。

我的做法是设置CUSTOMDRAW标志,保留每个可能不同节点的单个实例,并使每个节点指向此实例:3个Item_C节点将分别指向相同的唯一Item_C实例。

因此,当我更改Item_C上的数据时,只需要在3个Item_C节点上调用InvalidateRect()即可反映对(单个)更改数据所做的更改。

我想你可以在这里应用相同的策略。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接