【问题标题】:Qt itemChanged signal with QTreeView model works only on first level items带有 QTreeView 模型的 Qt itemChanged 信号仅适用于第一级项目
【发布时间】:2016-06-12 21:26:31
【问题描述】:

我不知道我是否在我的 qt 代码中做错了什么。我只需要在每次项目数据更改时发出itemChanged 信号。 我使用以下代码制作模型:

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

我希望,每次更改项目时都会调用onChanged - 例如,编辑项目文本或单击复选框。 但在每种情况下,我只在“item1-...”级别项目(第一级项目)上触发了itemChanged 信号,而不是在 item2/3 级项目上。 为什么?我怎样才能使它正确?

PS:与 QTreeWidget 相同的代码可以完美运行,但我在我的应用程序中使用了多线程,我需要划分模型和视图。 QTreeWidget项不能在非gui线程中创建,qtreewidget不能使用自创建模型。这就是为什么我必须将 QTreeView 与 QStandardItem 一起使用的原因。

【问题讨论】:

    标签: c++ qt qtreeview qstandarditem


    【解决方案1】:

    我刚刚调试了一下情况,你没有得到信号的原因如下:当item的数据发生变化时,你在Qt源码中有这个:

    void QStandardItem::setData(...)
    {
       /* ... */
       if (d->model)
           d->model->d_func()->itemChanged(this);
    }
    

    另一方面,当向父项添加子项时,您有

    bool QStandardItemPrivate::insertRows(int row, const QList<QStandardItem*> &items)
    {
       /* ... */
       for (int i = 0; i < items.count(); ++i) {
         /* ... */
           item->d_func()->model = model;
       }
    }
    

    所以这意味着,项目需要一个指向模型的指针来通知模型有关更改,并且子项目的模型在插入时设置为父项目。现在您首先将子项添加到父项,然后将父项添加到其父项,将不可见的根作为一级项的父项。由于隐形根有模型,所以一级项发出信号,而其他项没有。

    一个简单的更改解决了这个问题:只需先将项目添加到其父项,然后附加子项,如下所示:

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

    【讨论】:

    • 它有效,thx)我建议问题出在树的构建方法上,但你说得清楚简单)
    【解决方案2】:

    我不知道为什么默认是子项模组不会导致父项被“更改”。我想作为一种解决方法,您可以将每个子 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;
    }
    

    应该发生的是,如果您更改 item3 级别记录,则信号应一直转发到 item1(您建议它正在工作),然后正常继续:

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

    我没有对此进行测试,但假设 item1 dataChanged() 信号对您有效(您的 cmets 建议)那么这应该有效。

    编辑

    啊,我认为这实际上可能无法如您所愿。我认为您将始终将 item1 指针发送到您的 onChanged() 插槽。如果您希望发送 item3 指针,那么您可能必须对 QStandardItem 进行子类化(创建一个继承 QStandardItem 的类),然后执行以下操作:

    • 添加一个发出的信号:itemChanged(QStandardItem*)
    • 添加槽:void itemHasChanged() {emit itemChanged(this);}
    • 在构造函数中将 dataChanged() 连接到 itemHasChanged()。

    然后在你的循环中你可以item1 = new myQStandardItem; 然后对于您添加的每个新项目,将它们直接连接到您的 onChanged() 插槽:

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

    如果你不能让模型为你做这件事(即 B 计划),那就有点额外的努力(但不是太多)......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 2021-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多