作为示例,我以the official example from Qt Documentation为例,添加了几行代码来演示该问题:
model.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]
model.cpp:
#include "model.h"
Animal::Animal(const QString &type, const QString &size)
: m_type(type), m_size(size)
{
}
QString Animal::type() const
{
return m_type;
}
QString Animal::size() const
{
return m_size;
}
AnimalModel::AnimalModel(QObject *parent)
: QAbstractListModel(parent)
, m_myProperty(0)
{
}
void AnimalModel::addAnimal(const Animal &animal)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_animals << animal;
endInsertRows();
}
int AnimalModel::rowCount(const QModelIndex & parent) const {
Q_UNUSED(parent);
return m_animals.count();
}
QVariant AnimalModel::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() >= m_animals.count())
return QVariant();
const Animal &animal = m_animals[index.row()];
if (role == TypeRole)
return animal.type();
else if (role == SizeRole)
return animal.size();
return QVariant();
}
bool AnimalModel::insertRows(int position, int rows, const QModelIndex &index)
{
beginInsertRows(index, position, position + rows - 1);
for (int row = 0; row < rows; ++row) {
m_animals.insert(position, Animal("new type", "new animal"));
}
endInsertRows();
return true;
}
void AnimalModel::addAnimal()
{
insertRow(0);
m_myProperty = m_animals.count();
emit myPropertyChanged();
}
//![0]
QHash<int, QByteArray> AnimalModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[TypeRole] = "type";
roles[SizeRole] = "size";
return roles;
}
//![0]
最后是view.qml:
import QtQuick 2.0
import QtQuick.Controls 2.2
//![0]
Column {
ListView {
id: list
width: 200; height: 250
model: myModel
delegate: Text {
text: index + ": Animal: " + type + ", " + size + ", " + list.model.myProperty
Connections {
target: myModel
onMyPropertyChanged: {
console.log(index + ", " + list.model.myProperty)
}
}
}
}
Button {
onClicked: {
myModel.addAnimal()
}
}
}
//![0]
非常简单。在按下按钮并调用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错误吗?我使用的是Qt 5.9.5。
发布于 2018-05-28 18:16:17
当您使用insertRow(0)
时,您将插入到位置0,因此前面的0元素现在将是具有连接并将接收信号的元素。
因此,当按下所单击的元素时,最后插入的元素将没有连接,因此不会通知它。
为了说明这一点,我将一步一步地解释:
总之,委托的创建是在发出myPropertyChanged
信号之后进行的,因此插入的委托不会被通知,其他人会收到通知,而且由于您的插入始终位于第一个位置,因此它永远不会被打印为qml: 0, n
为了以图形方式理解,假设存在代理,当它们已经存在时,它们将收到通知:
0 0 (+)
0 (+) 1 (+) 1 (+)
1 (+) 2 (+) 2 (+)
2 (+) 3 (+) 3 (+)
... --> clicked --> myPropertyChanged --> ... --> 4 (+)
n (+) n+1 (+) n+1 (+)
(+):表示有连接
更多解释:
要明确的是,事件循环的规则如下:顺序任务优先执行,如果信号不紧急,则对信号进行等待调用。
让我们更详细地分析您的代码:
前面的几行是按顺序执行的,所以在第一步的末尾,模型中已经有了一个新元素,但是视图并没有更新,因为为此,代码必须返回到事件循环,并且必须完成步骤3的执行。
在完成步骤3之后,信号任务被执行,所以您要做的是创建委托和连接,所以现在您将优先考虑myPropertyChanged
信号,并调用减去最后一个连接的现有连接,因为在发出信号时它并不存在。
总之,只有当信号发出信号时存在的时隙将被调用,在信号发出之后立即创建的新连接直到时隙调用将不被调用。
https://stackoverflow.com/questions/50563761
复制相似问题