C++ TreeView中的层次数据和TreeView更新技术

C++ TreeView中的层次数据和TreeView更新技术,c++,qt,treeview,design-patterns,qt3,C++,Qt,Treeview,Design Patterns,Qt3,我在树视图中显示了很多(层次)数据(可能是大约20K个项目或更多,包括子项目)。我的数据的特殊问题是,树视图中显示的每个对象都可以存在于许多树视图项中。我的意思是,我可能有这样一个层次结构: 项目A->项目B->项目c Item_B->Item_C ItemC 假设项目A包含项目B,其中包含项目C,如上所示。这意味着我的列表还将显示项目B和项目C的层次结构。现在考虑一个对象发生的事情,如 ItMyB.(例如名称更改)。那当然两项都有 必须更新。现在考虑具有复杂层次结构的树视图中的数以千计项。您将

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

  • 项目A->项目B->项目c
  • Item_B->Item_C
  • ItemC
  • 假设
    项目A
    包含
    项目B
    ,其中包含
    项目C
    ,如上所示。这意味着我的列表还将显示
    项目B
    项目C
    的层次结构。现在考虑一个对象发生的事情,如<代码> ItMyB.<代码>(例如名称更改)。那当然两项都有 必须更新。现在考虑具有复杂层次结构的树视图中的数以千计项。您将使用什么策略来更新treeview?速度当然是这里主要关注的问题,但也很容易使用和维护。目前,我持有列表项到对象的内部映射,反之亦然,以便快速查找和更新项。这是正确的策略吗?通过在每次更新后重新创建列表,我可以扔掉很多代码,但我不知道哪些项目路径被展开或折叠。我怎样才能解决这个问题?我应该将扩展路径存储在内部容器中吗

    多谢各位


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

    < P> >我使用Windows TeeVIEW通用控件。 我所做的是设置CUSTOMDRAW标志,为每个可能的不同节点保留一个实例,并使每个节点指向该实例:3个Item_C节点都有一个指向相同唯一Item_C实例的指针

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


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

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

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


    我不太喜欢Qt的模型/视图实现(给定的模型/视图/控制器设计模式非常古老),但它有助于在GUI中组织数据

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


    请参阅。

    我使用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;
    };
    
    类引用计数器
    {
    公众:
    //单例模式。实现由您决定。
    静态引用计数器&get();
    无效添加(常量树数据和数据){
    mCounter[data.getId()]。推回(&data);
    }
    无效删除(常量树数据和数据){
    常量计数器类型::常量迭代器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.擦除(itr);
    }
    }
    }
    typedef std::vector ItemType;
    ItemType::迭代器开始(const TreeData&data){
    常量计数器类型::常量迭代器itr=mCounter.find(data.getId());
    if(itr!=mCounter.end()){
    返回itr->second.begin();
    }
    //其他情况由你决定。
    }
    ItemType::迭代器端(const TreeData和data){
    常量计数器类型::常量迭代器itr=mCounter.find(data.getId());
    if(itr!=mCounter.end()){
    返回itr->second.end();
    }
    //其他情况由你决定。
    }
    私人:
    typedef std::映射计数器类型;
    计数器式计数器;
    };
    树形纲
    {
    公众:
    TreeData(){ReferenceCounter::get().add(*this);}
    ~TreeData(){ReferenceCounter::get().remove(*this);}
    //获取数据库行或树正在跟踪的任何内容。
    int getId()常量;
    };
    
    因此,给定任何TreeData,您可以在引用计数器中查找具有匹配ID的所有其他TreeData。这使得名字和内容保持最新变得简单快捷。我们的树处理超过1000000个节点,没有问题。在我的实现中,为了便于使用,我将迭代内容封装在
    boost::iterator\u facade
    类中