TreeView和TreeView更新技术中的分层数据

时间:2009-08-01 20:20:46

标签: c++ qt treeview design-patterns qt3

我有很多(hierachical)数据,我在TreeView中显示(可能是大约20K项目或更多,包括儿童项目)。我的数据的一个特殊问题是树视图中显示的每个对象都可以存在于许多树视图项中。我的意思是我可能有这样的层次结构:

  1. Item_A -> Item_B -> ItemC
  2. Item_B -> Item_C
  3. ItemC
  4. 让我们假设Item_A包含Item_B,其中包含Item_C,如上所示。这意味着我的列表还会显示Item_BItem_C的层次结构。现在考虑一个对象显示为Item_B(例如名称更改)。然后当然这两个项目 必须更新。现在考虑具有复杂层次结构的树视图中的数千个项目。您将使用什么策略来更新树视图?速度当然是这里的主要问题,但也易于使用和维护。目前,我将列表项的内部映射保存到对象,反之亦然,以便快速查找和更新项目。这是正确的策略吗?通过在每次更新后重新创建列表,我可以抛弃大量代码,但我不知道哪些项目路径被展开或折叠。我怎么能解决这个问题?我应该在内部容器中存储扩展路径吗?

    谢谢。

    PS:编程语言是C ++,GUI lib是QT3。

4 个答案:

答案 0 :(得分:1)

我很久以前做过类似的事情,使用windows TreeView常用控件。

我所做的是设置CUSTOMDRAW标志,保留每个可能的不同节点的单个实例,并使每个节点指向此实例:3个Item_C节点每个都有一个指向同一个唯一Item_C实例的指针。

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

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

答案 1 :(得分:1)

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

如果您从未这样做过,那么您必须编写自己的模型,这可能会很乏味,但是一旦设置完成,您就可以轻松地引用/更新同一对象的多个实例。选择/多项选择也可以处理。

我不是Qt的模型/视图实现的忠实粉丝(给定模型/视图/控制器设计模式已经很老了)但它有助于在gUI中组织数据

答案 2 :(得分:1)

使用widget->setUpdatesEnabled(false)停用更新,然后编辑您想要的所有内容,然后使用widget->setUpdatesEnabled(true)将其重命名。

请参阅Qt documentation

答案 3 :(得分: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类中以便于使用。