I don't know if I do something wrong in my qt code. I just need that itemChanged
signal is emitted every time when item data changed.
I use following code to make the model:
QStandardItemModel* model = new QStandardItemModel;
QStandardItem *parentItem = model->invisibleRootItem();
QList<QStandardItem*> itemList1;
QList<QStandardItem*> itemList2;
QList<QStandardItem*> itemList3;
QStandardItem* item1;
QStandardItem* item2;
QStandardItem* item3;
for (int i = 0; i < 3; ++i)
{
item1 = new QStandardItem;
item1->setText("item1-" + QString::number(i));
for (int i = 0; i < 3; ++i)
{
item2 = new QStandardItem;
item2->setText("item2-" + QString::number(i));
for (int i = 0; i < 3; ++i)
{
item3 = new QStandardItem;
item3->setText("item3-" + QString::number(i));
itemList3 << item3;
}
item2->appendRows(itemList3);
itemList3.clear();
itemList2 << item2;
}
item1->appendRows(itemList2);
itemList2.clear();
itemList1 << item1;
}
parentItem->appendRows(itemList1);
itemList1.clear();
ui.treeView->setModel(model);
QObject::connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onChanged(QStandardItem*)));
and I want, that onChanged
will be called every time when item changed - for example, item text edited or checkbox clicked.
But in each case I have triggered itemChanged
signal only on "item1-..." level items (first level items), not on item2/3 level items.
Why? And how can I make it correct?
PS: same code with QTreeWidget works perfectly, but I use multithreading in my app and I need to divide model and view. QTreeWidget items can't be created in non-gui thread and qtreewidget can't use self-created model. That's the reason why I must to use QTreeView with QStandardItem.
I just debugged the situation, the reason why you don't get the signal is as follows: When the item's data is changed, you have this in the Qt source:
void QStandardItem::setData(...)
{
/* ... */
if (d->model)
d->model->d_func()->itemChanged(this);
}
On the other hand, when adding a child item to a parent, you have
bool QStandardItemPrivate::insertRows(int row, const QList<QStandardItem*> &items)
{
/* ... */
for (int i = 0; i < items.count(); ++i) {
/* ... */
item->d_func()->model = model;
}
}
So this means, items need a pointer to the model to notify the model about the change, and the model of a child item is set to the parent's item at the time of insertion. Now you add the children to the parent first, and then the parents to their parents, with the invisible root as the parent of level-1 items. As the invisible root has a model, the level-1 items send the signal, but the others do not.
A simple change fixes this: Just add the item to its parent first, and then append the children, like this:
for (int i = 0; i < 3; ++i)
{
item1 = new QStandardItem;
item1->setText("item1-" + QString::number(i));
parentItem->appendRow(item1);
for (int i = 0; i < 3; ++i)
{
item2 = new QStandardItem;
item2->setText("item2-" + QString::number(i));
item1->appendRow(item2);
for (int i = 0; i < 3; ++i)
{
item3 = new QStandardItem;
item3->setText("item3-" + QString::number(i));
item2->appendRow(item3);
}
}
}