首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >QML连接在新插入的行中不起作用吗?

QML连接在新插入的行中不起作用吗?
EN

Stack Overflow用户
提问于 2018-05-28 18:00:21
回答 1查看 278关注 0票数 0

作为示例,我以the official example from Qt Documentation为例,添加了几行代码来演示该问题:

model.h:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
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()之后,我希望看到控制台输出如下所示:

代码语言:javascript
复制
qml: 0, 4
qml: 1, 4
qml: 2, 4
qml: 3, 4

但我看到的却是:

代码语言:javascript
复制
qml: 1, 4
qml: 2, 4
qml: 3, 4

但是,信号肯定会发出(和接收),因为UI不仅显示新添加的具有更新的动物列表大小的项,而且所有其他行都已更新。那么为什么新行没有接收到onMyPropertyChanged呢?

这是一个Qt错误吗?我使用的是Qt 5.9.5。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-28 18:16:17

当您使用insertRow(0)时,您将插入到位置0,因此前面的0元素现在将是具有连接并将接收信号的元素。

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

为了说明这一点,我将一步一步地解释:

  • 在第一个插入中没有元素,因此没有人接收信号。
  • 在第二个插入中,前一个0元素将是当前的1,并且它具有连接,因此它将被通知。
  • 在第三个插入中,前一个0元素将是当前的1,前一个元素将是当前的2,因此1,2具有连接并将被通知。

总之,委托的创建是在发出myPropertyChanged信号之后进行的,因此插入的委托不会被通知,其他人会收到通知,而且由于您的插入始终位于第一个位置,因此它永远不会被打印为qml: 0, n

为了以图形方式理解,假设存在代理,当它们已经存在时,它们将收到通知:

代码语言:javascript
复制
                                            0           0  (+)
0 (+)                                       1  (+)      1  (+)
1 (+)                                       2  (+)      2  (+)
2 (+)                                       3  (+)      3  (+)
... --> clicked --> myPropertyChanged -->  ...     -->  4  (+)
n (+)                                      n+1 (+)     n+1 (+)

(+):表示有连接

更多解释:

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

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

  1. insertRow(0);
  2. m_myProperty = m_animals.count();
  3. emit myPropertyChanged();

前面的几行是按顺序执行的,所以在第一步的末尾,模型中已经有了一个新元素,但是视图并没有更新,因为为此,代码必须返回到事件循环,并且必须完成步骤3的执行。

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

总之,只有当信号发出信号时存在的时隙将被调用,在信号发出之后立即创建的新连接直到时隙调用将不被调用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50563761

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档