简体   繁体   English

使用QTreeView模型的Qt itemChanged信号仅适用于第一级项目

[英]Qt itemChanged signal with QTreeView model works only on first level items

I don't know if I do something wrong in my qt code. 我不知道我的qt代码中是否有错误。 I just need that itemChanged signal is emitted every time when item data changed. 我只需要在每次项目数据更改时发出itemChanged信号。 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. 我希望,每次项目更改时都会调用onChanged - 例如,项目文本已编辑或复选框已单击。 But in each case I have triggered itemChanged signal only on "item1-..." level items (first level items), not on item2/3 level items. 但是在每种情况下我都只在“item1 -...”级别项目(第一级项目)上触发了itemChanged信号,而不是在item2 / 3级别项目上。 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. PS:与QTreeWidget完全相同的代码,但我在我的应用程序中使用多线程,我需要划分模型和视图。 QTreeWidget items can't be created in non-gui thread and qtreewidget can't use self-created model. 无法在非gui线程中创建QTreeWidget项,qtreewidget不能使用自创模型。 That's the reason why I must to use QTreeView with QStandardItem. 这就是我必须将QTreeView与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: 我只是调试了这种情况,你没有得到信号的原因如下:当项目的数据发生变化时,你在Qt源代码中有这个:

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. 现在,首先将子项添加到父项,然后将父项添加到父项,将不可见的根作为level-1项的父项。 As the invisible root has a model, the level-1 items send the signal, but the others do not. 由于隐形根具有模型,因此1级项目发送信号,而其他项目则不发送信号。

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);
        }
    }
}

I am not sure why the default is for child item mods not being causing the parent item to be "changed". 我不确定为什么默认情况下子项mods不会导致父项“被更改”。 I suppose as a workaround you could connect each childs DataChanged() signal to its parents DataChanged() signal, so that the signal propagates up the hierarchy, something like: 我想作为一种解决方法,您可以将每个子DataChanged()信号连接到其父DataChanged()信号,以便信号在层次结构中向上传播,如:

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;
            connect(item3, SIGNAL(DataChanged()), item2, SIGNAL(DataChanged()));
        }
        item2->appendRows(itemList3);
        itemList3.clear();
        itemList2 << item2;
        connect(item2, SIGNAL(DataChanged()), item1, SIGNAL(DataChanged()));
    }
    item1->appendRows(itemList2);
    itemList2.clear();
    itemList1 << item1;
}

What should happen is that if you change an item3 level record the signal should be forwarded all the way up to item1 (which you suggest is working) and then continue as normal: 应该发生的是,如果你更改了一个item3级别的记录,那么信号应该一直转发到item1(你建议它正在工作),然后继续正常:

item3 ---DataChanged()---> item2
item2 ---DataChanged()---> item1
item1 ---DataChanged()---> model
model ---itemChanged()---> onChanged()

I have not tested this, but assuming the item1 dataChanged() signal is working for you (which your comments suggest) then this should work. 我没有测试过这个,但是假设item1 dataChanged()信号对你有用(你的评论建议),那么这应该有效。

Edit 编辑

Ah, I think this may not actually work as you want it. 啊,我认为这可能实际上并不像你想要的那样。 I think you will always get an item1 pointer sent to your onChanged() slot. 我想你总会得到一个发送到你的onChanged()插槽的item1指针。 If you want the item3 pointer sent then you may have to sub class QStandardItem (make a class that inherits QStandardItem) and then do the following: 如果你想发送item3指针,那么你可能需要子类QStandardItem(创建一个继承QStandardItem的类),然后执行以下操作:

  • Add a signal that emits: itemChanged(QStandardItem*) 添加发出的信号: itemChanged(QStandardItem*)
  • add a slot: void itemHasChanged() {emit itemChanged(this);} 添加一个槽: void itemHasChanged() {emit itemChanged(this);}
  • connect dataChanged() to itemHasChanged() in the constructor. 在构造函数中将dataChanged()连接到itemHasChanged()。

Then in your loop you can item1 = new myQStandardItem; 然后在你的循环中你可以item1 = new myQStandardItem; And then for each new item you add directly connect them to your onChanged() slot: 然后为您添加的每个新项目直接将它们连接到您的onChanged()插槽:

QObject::connect(itemX, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onChanged(QStandardItem*)));

It's a bit of an extra effort (but not too much), if you can't get the model to do it for you (ie a plan-B)... 这是一个额外的努力(但不是太多),如果你不能让模型为你做(即计划-B)......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM