crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Странное поведение QTreeWidgetItem::removeChild
chereppiter
  опции профиля:
сообщение 18.12.2012, 10:56
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 30
Регистрация: 12.11.2012
Пользователь №: 3595

Спасибо сказали: 0 раз(а)




Репутация:   0  


Есть функция построения дерева (QTreeWidget), в которой для каждого элемента верхнего уровня рекурсивно вызывается функция добавления отпрысков:

void addChilds(QTreeWidgetItem* item, int id)
{
QTreeWidgetItem* child;
for (unsigned int i = 0; i < nodes.size(); ++i)
{
if (nodes[i].parentid == id)
{
child = new QTreeWidgetItem(item);
child->setText(0, QString::fromUtf8(nodes[i].name.c_str()));
addChilds(child, nodes[i].id);
if (!child->childCount())
{
item->removeChild(child);
delete child;
}
}

}
}

По возвращению из рекурсивной addChilds, если у текущего чаилда детей нет, то он удаляется. Ситуация такая: на одной из итераций цикла к item был добавлен child (и не был удалён, т.к. у него тоже есть дети). На одной из последующих итераций создаётся child, для которого потом childCount оказывается 0, поэтому он удаляется (item->removeChild(child)). При этом почему-то вместе с этим отпрыском удаляется и тот, который был добавлен на одной из предыдущих итераций. Проблема решается исключением из вышеприведённого кода строчки:

item->removeChild(child);

Т.е. если удаление выглядит так:

if (!child->childCount())
{
delete child;
}

, то всё работает нормально.
Кто-нибудь знает причину этого загадочного явления?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Алексей1153
  опции профиля:
сообщение 19.12.2012, 14:37
Сообщение #2


фрилансер
******

Группа: Участник
Сообщений: 2941
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


chereppiter, что делает этот метод, можно прочитать в доке
Цитата
void QTreeWidgetItem::removeChild ( QTreeWidgetItem * child )
Removes the given item indicated by child. The removed item will not be deleted.

метод работает так, как ему и положено, ошибка где-то у тебя. Неправилен сам подход к дереву, поэтому появляется дополнительная возможность ошибки - а где она, это без отладчика так сразу я не вижу, конечно.

Сделай минимального размера дерева, где ошибка появляется , затем отладчиком прошагай рекурсию, обращая внимания на адреса элементов и момент, когда удалился не тот элемент, который ожидалось

Ну и про правильный подход:

//класс элемента
class MyQTreeWidgetItem:public QTreeWidgetItem
{
    MyQTreeWidgetItem* m_parent;

    uint32_t m_id;//некая дополнительная инфа элемента.

    QTreeWidgetItem(QTreeWidgetItem* m_parent=0):m_parent(m_parent)
    {
    }
    ....
    ....
};

typedef std::multimap<
     MyQTreeWidgetItem* //parent
    ,MyQTreeWidgetItem* //child
    > td_my_tree; //это тип контейнера, содержащего ВСЁ наше дерево

//класс модели дерева
class MyTree
{
    td_my_tree m_tree;//контейнер с указателями на все элементы дерева
};



пример создания элементов дерева (легко переделать в рекурсивный вариант)
//создание корневого элемента:
MyQTreeWidgetItem* root=new MyQTreeWidgetItem(0);
m_tree.insert(td_my_tree::value_type(root.m_parent,root));

//добавляем ему два потомка
MyQTreeWidgetItem* с1=new MyQTreeWidgetItem(root);
MyQTreeWidgetItem* с2=new MyQTreeWidgetItem(root);

m_tree.insert(td_my_tree::value_type(с1.m_parent,с1));
m_tree.insert(td_my_tree::value_type(с2.m_parent,с2));

//....


тут мы контролируем всю подноготную жизни элементов , всегда их все можем быстро найти и посмотреть. По указателю на потомка всегда найдём его родителя (m_parent) , а по мапе - всю ветку элемента. При удалении ветки следует рекурсивно пройтись по её потомкам и
1) вариант первый - удалить их из мапы (но не из кучи, так как это сделает сам QTreeWidgetItem) , затем delete корень ветки
2) вариант второй - удалить их из мапы , из всех родительских элементов и из кучи , затем delete корень ветки (первый вариант в нашем случае красивее)

показать наше дерево в QTreeWidget - метод
void QTreeWidget::insertTopLevelItem ( int index, QTreeWidgetItem * item )
, куда надо передать корень

ну и не забывать отключать его от QTreeWidget , чтобы QTreeWidget не удалил всё сам в деструкторе, когда это нужно

Попробуй :)

Сообщение отредактировал Алексей1153 - 19.12.2012, 16:12
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме
- chereppiter   Странное поведение QTreeWidgetItem::removeChild   18.12.2012, 10:56
- - Алексей1153   в поставленном вопросе много неизвестного: 1) чем ...   18.12.2012, 23:54
- - chereppiter   1) Чтобы было более понятно, приведу полный текст ...   19.12.2012, 11:00
- - Алексей1153   chereppiter, что делает этот метод, можно прочитат...   19.12.2012, 14:37
- - chereppiter   Не понимаю, в чём неправильность моего подхода к д...   19.12.2012, 17:55
- - Алексей1153   chereppiter, тогда прикрепи проект (удали лишнее),...   20.12.2012, 6:56
- - chereppiter   Создал отдельный маленький тестовый проект. Глючна...   20.12.2012, 15:53
- - Алексей1153   в общем, вскрытие показало, что чукча умер от вскр...   21.12.2012, 0:25
- - iReset   Насколько я понял при беглом просмотре исходников,...   21.12.2012, 9:13
- - Алексей1153   iReset, вообще, забавная ситуация - указываем конк...   21.12.2012, 11:10
|- - iReset   Цитата(Алексей1153 @ 21.12.2012, 12:10) i...   21.12.2012, 12:30
- - chereppiter   Ну вот, совместными усилиями докопались до истины....   21.12.2012, 11:26


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.11.2024, 2:26