C++ QML连接在新插入的行中不工作?

C++ QML连接在新插入的行中不工作?,c++,qt,qml,qabstractitemmodel,C++,Qt,Qml,Qabstractitemmodel,作为示例,我选取并添加了几行代码来演示问题: 型号h: #include <QAbstractListModel> #include <QStringList> //![0] class Animal { public: Animal(const QString &type, const QString &size); //![0] QString type() const; QString size() const; pri

作为示例,我选取并添加了几行代码来演示问题:

型号h:

#include <QAbstractListModel>
#include <QStringList>

//![0]
class Animal
{
public:
    Animal(const QString &type, const QString &size);
//![0]

    QString type() const;
    QString size() const;

private:
    QString m_type;
    QString m_size;
//![1]
};

class AnimalModel : public QAbstractListModel
{
    Q_OBJECT

    Q_PROPERTY(int myProperty READ myProperty NOTIFY myPropertyChanged)

signals:
    void myPropertyChanged();

public:
    enum AnimalRoles {
        TypeRole = Qt::UserRole + 1,
        SizeRole
    };

    AnimalModel(QObject *parent = 0);
//![1]

    void addAnimal(const Animal &animal);

    int rowCount(const QModelIndex & parent = QModelIndex()) const;

    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

    // my code starts
    virtual bool insertRows(int position, int rows,
                            const QModelIndex &index = QModelIndex()) override;
    virtual Qt::ItemFlags flags(const QModelIndex &index) const override {
        return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
    }
    int myProperty() const {
        return m_myProperty;
    }
    int m_myProperty;

public slots:
    void addAnimal();
        // my code ends

protected:
    QHash<int, QByteArray> roleNames() const;
private:
    QList<Animal> m_animals;
//![2]
};
//![2]
很简单。按下按钮并调用
addAnimal()
后,我希望看到控制台输出如下:

qml: 0, 4
qml: 1, 4
qml: 2, 4
qml: 3, 4
但我看到的是:

qml: 1, 4
qml: 2, 4
qml: 3, 4
但是,该信号肯定会被发出(并被接收),因为UI不仅会显示具有更新的动物列表大小的新添加项目,而且所有其他行都已更新。那么,为什么新行没有收到
onMyPropertyChanged

这是一个Qt错误吗?我正在使用Qt5.9.5


当您使用插入行(0)插入位置0时,前一个0元素现在将是具有连接并接收信号的元素

因此,当按下单击的按钮时,最后插入的元素将没有连接,因此不会通知它


为了举例说明,我将逐步解释:

  • 在第一次插入中,没有元件,因此没有人接收信号

  • 在第二次插入中,前一个0元素将是当前的1,并且它具有连接,因此将通知它

  • 在第三次插入中,前一个0元素将是当前的1,前一个元素将是当前的2,因此1、2具有连接并将被通知

总之,代理的创建是在发出
myPropertyChanged
信号后进行的,因此插入的代理不会得到通知,其他代理会得到通知,并且由于您的插入始终位于第一个位置,因此将永远不会打印
qml:0,n

要以图形方式理解,请假设存在代表,并且他们已经存在,他们将收到通知:

                                            0           0  (+)
0 (+)                                       1  (+)      1  (+)
1 (+)                                       2  (+)      2  (+)
2 (+)                                       3  (+)      3  (+)
... --> clicked --> myPropertyChanged -->  ...     -->  4  (+)
n (+)                                      n+1 (+)     n+1 (+)
(+):表示存在连接


更多解释:

需要明确的是,事件循环的规则如下:顺序任务优先执行,信号调用在不紧急时等待

让我们更详细地分析您的代码:

  • 插入行(0)
  • m_myProperty=m_animals.count()
  • 发出myPropertyChanged() 前面的行是按顺序执行的,因此在第一步结束时,模型中已经有了一个新元素,但视图尚未更新,因为为此,代码必须返回到事件循环,并且必须完成第3步的执行

    在完成步骤3之后,信号任务将被执行,因此您要做的是创建委托和连接,因此现在您将优先考虑
    myPropertyChanged
    信号,并调用现有连接减去上一个连接,因为在发出信号时它不存在



    总之,只有信号发出时存在的插槽才会被调用,在信号发出后立即创建的新连接直到插槽调用才会被调用。

    只是一个小更正:列表从三个预填充的动物开始,因此第一个项目符号不正确。你写道“委托的创建是在发出myPropertyChanged信号之后”——这很公平,但委托的创建时间到底是什么时候?@MiroKropacek在我的第一点中,我假设有0个委托,但在任何情况下,我的解释都是有效的,如果有3个委托,就会通知他们。该连接是在创建委托后提供的。我仍然不明白为什么委托创建得不够快?我是说,我们插入一行,对吧。发出信号rowsInserted()。现在我假设在这一点的某个地方创建了项和委托。我调用emit myPropertyChanged();之后。那么,为什么对这个可怜的委托来说太早了呢?@MiroKropacek等一下,我只是在我的回答中添加了@eyllansc:我的一个用例是让TextField的readOnly标志取决于这个变量的状态。然而,当我输入这个时,我意识到也许我可以通过引入一个单独的角色来避免这个异步地狱。不管怎样,你的意见非常有用!
    qml: 1, 4
    qml: 2, 4
    qml: 3, 4
    
                                                0           0  (+)
    0 (+)                                       1  (+)      1  (+)
    1 (+)                                       2  (+)      2  (+)
    2 (+)                                       3  (+)      3  (+)
    ... --> clicked --> myPropertyChanged -->  ...     -->  4  (+)
    n (+)                                      n+1 (+)     n+1 (+)