Иерархические данные в технике обновления TreeViews и TreeView - PullRequest
3 голосов
/ 02 августа 2009

У меня есть много (иерархических) данных, которые я показываю в TreeView (может быть около 20 тыс. Элементов или более, включая дочерние элементы). Особая проблема с моими данными заключается в том, что каждый объект, отображаемый в древовидном представлении, может существовать во многих древовидных элементах. Под этим я подразумеваю, что у меня может быть такая иерархия:

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

Предположим, что Item_A содержит Item_B, который содержит Item_C, как показано выше. Это означает, что мой список также покажет иерархию Item_B и Item_C. Теперь посмотрим, что происходит с объектом, показанным как Item_B (например, изменение имени). Тогда, конечно, оба пункта должен быть обновлен. Теперь рассмотрим тысячи элементов в древовидной структуре со сложной иерархией. Какую стратегию вы бы использовали для обновления дерева? Скорость, конечно, является главной заботой здесь, но также и простота использования и обслуживания. В настоящее время я храню внутренние отображения элементов списка на объектах и ​​наоборот, чтобы быстро находить и обновлять элементы. Это правильная стратегия? Восстанавливая список после каждого обновления, я могу выбросить много кода, но я не знаю, какие пути элементов были расширены или свернуты. Как я мог решить эту проблему? Должен ли я хранить расширенные пути во внутреннем контейнере?

Спасибо.

PS: язык программирования - C ++, а библиотека GUI - QT3.

Ответы [ 4 ]

1 голос
/ 15 декабря 2009

Я решил аналогичную проблему, используя дерево управления 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 вы можете найти все другие TreeData с соответствующими идентификаторами в счетчике ссылок. Это позволяет легко и быстро обновлять имена и прочее. Наше дерево обрабатывает более 1 000 000 узлов без проблем. В моей реализации я поместил материал итерации в класс boost::iterator_facade для более удобного использования.

1 голос
/ 02 сентября 2009

Используйте модель / вид Qt4, если вы можете использовать Qt4 в своем проекте.

Вам придется написать свою собственную модель, которая может быть утомительной, если вы никогда этого не делали, но после настройки вы можете легко ссылаться на / обновлять несколько экземпляров одного и того же объекта. Выборы / множественный выбор также могут быть обработаны.

Я не большой поклонник реализации модели / представления Qt (данный шаблон проектирования модели / представления / контроллера довольно стар), но это помогает организовать данные в графических интерфейсах

1 голос
/ 09 сентября 2009

Отключить обновления с помощью widget->setUpdatesEnabled(false), затем отредактировать все, что вы хотите, а затем восстановить его с помощью widget->setUpdatesEnabled(true).

См. Документацию Qt .

1 голос
/ 05 августа 2009

Я делал нечто подобное очень давно, используя общий элемент управления TreeView в Windows.

Я установил флаг CUSTOMDRAW, сохранил один экземпляр каждого возможного отдельного узла и заставил каждый узел указывать на этот экземпляр: каждый из 3 узлов Item_C будет иметь указатель на один и тот же уникальный экземпляр Item_C.

Итак, когда я изменяю данные в Item_C, мне нужно было только вызвать InvalidateRect () на 3 узлах Item_C, чтобы отразить изменения, сделанные в (одиночных) измененных данных.

Полагаю, вы могли бы применить ту же стратегию здесь.

...