3

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

  1. Item_A -> Item_B -> ItemC
  2. Item_B -> Item_C
  3. ItemC

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

谢谢你。

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

4

4 回答 4

1

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

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

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

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

于 2009-08-05T04:39:03.160 回答
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类中以便于使用。

于 2009-12-15T02:18:08.183 回答
1

使用 禁用更新widget->setUpdatesEnabled(false),然后编辑您想要的所有内容,然后使用 重新启用它widget->setUpdatesEnabled(true)

请参阅Qt 文档

于 2009-09-09T11:20:42.183 回答
1

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

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

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

于 2009-09-02T19:50:12.547 回答