4

Consider I have QTreeWidget with following items hierarchy:

top_item
  |--child

Every item has assigned with setItemWidget() widget. I need to insert another child between my first two elements like this :

top_item
  |--another_child
     |--child

I trying to do that with following code:

QTreeWidgetItem* top_item = new QTreeWidgetItem;
ui->treeWidget->addTopLevelItem(top_item);
QTreeWidgetItem* child_item = new QTreeWidgetItem;
top_item->addChild(child_item);

ui->treeWidget->setItemWidget(top_item, 0, new QPushButton);
ui->treeWidget->setItemWidget(child_item, 0, new QPushButton);

// ---- let's insert another child ----
auto last_children = top_item->takeChildren();

QTreeWidgetItem* another_child_item = new QTreeWidgetItem;
top_item->insertChild(0, another_child_item);
ui->treeWidget->setItemWidget(another_child_item, 0, new QPushButton);

another_child_item->addChildren(last_children);

It works fine except one moment — it lost assigned widgets. I've tried to take and save the widgets before taking children with

QWidget* widget_from_child_item = ui->treeWidget->itemWidget(child_item, 0);
ui->treeWidget->removeItemWidget(child_item, 0);

but after calling takeChildren() all assigned widgets have been deleted and app is crashing after reassigning the widgets with setItemWidget().

What is my mistake?

Jenz
  • 8,009
  • 6
  • 38
  • 69
MaxNes
  • 81
  • 1
  • 1
  • 4

3 Answers3

1

Another way to do the same thing:

QTreeWidgetItem *child = ui->treeWidget->currentItem();
QTreeWidgetItem *parent = child->parent();

if(parent)
{
    QTreeWidgetItem *another_child = new QTreeWidgetItem();
    another_child->setText(0,"another_child");
    parent->addChild(another_child);
    another_child->addChild(parent->takeChild(parent->indexOfChild(child)));
}
Rémi
  • 432
  • 1
  • 13
  • 19
1

I've recognized by Qt documentation that QWidget isn't actually linked to QTreeWidgetItem: both methods QTreeWidget::setItemWidget and QTreeWidget::itemWidget have a comment

Note: The tree takes ownership of the widget.

In my case (insert child between others parent and child) I've implemented a next solution:

  1. Implement get_copy() method for my widget
  2. Before taking item from QTreeWidget copying a linked widgets
  3. After inserting new item and moving old item, assign copied widgets to appropriate QTreeWidgetItem

Here a small example:

void insert_tree_item(i_tree_item* new_widget_item)
{
  QTreeWidgetItem* current_item = _tree_widget->currentItem();

  if(current_item->childCount())
  {
    QList<QWidget*> widgets;
    widgets.push_front(dynamic_cast<QWidget*>(new_widget_item));
    QTreeWidgetItem* ptr = current_item->child(0);
    while(ptr != nullptr)
    {
        QWidget* widget = _tree_widget->itemWidget(ptr, 0);
        widgets.push_back(dynamic_cast<i_tree_item*>(widget)->get_copy());
        auto prev_ptr = ptr;
        ptr = ptr->child(0);
        if(ptr == nullptr)
        {
            prev_ptr->addChild(new QTreeWidgetItem);
        }
    }
    ptr = current_item->child(0);
    while(widgets.count() != 0)
    {
        _tree_widget->setItemWidget(ptr, 0, widgets.takeFirst());
        ptr = ptr->child(0);
    }
  }
  else
  {
    QTreeWidgetItem* new_item = new QTreeWidgetItem;
    current_item->addChild(new_item);
    _tree_widget->setItemWidget(new_item, 0, dynamic_cast<QWidget*>(new_widget_item));
  }
}
MaxNes
  • 81
  • 1
  • 1
  • 4
0
void insertAParent() {
   if (tree->selectedItems().count() != 1)
      return;

   QTreeWidgetItem *item = tree->selectedItems().front();
   QTreeWidgetItem *oldParent = item->parent();
   if (oldParent) {
       int index = oldParent->indexOfChild(item);
       item = oldParent->takeChild(index);
       QTreeWidgetItem *newParent = new QTreeWidgetItem;
       newParent->setText(0, tr("Something"));
       oldParent->insertChild(index, newParent);
       newParent->insertChild(0, item);
   }
}
Marek R
  • 23,155
  • 5
  • 37
  • 107
  • problem is not how to insert a child into existent hierarchy, problem is how to save children's widgets. – MaxNes Sep 19 '14 at 09:50
  • try my solution. If I understand correctly you have messed up usage of `removeItemWidget` and `takeChildren`. Also try to improve question. – Marek R Sep 19 '14 at 09:56
  • Yes, it is a first thing that I had done: try your solution. Ok, thanks for advice, will try soon. – MaxNes Sep 19 '14 at 10:38