c++ - 为 QML 的 ListView 公开 QObjects 的 QAbstractListModel。好的做法?

标签 c++ qt model-view-controller qml observer-pattern

所以我有了使用 QObjects 的 Q_PROPERTY 而不是 QAbstractListModel 的角色名称的想法,以便将可通知的属性公开给 QML。

我的问题是这是否是一个好的做法,因为使用从 QAbstractItemModel 继承的类感觉有点不自然。

让我更详细地解释一下。
因此,为 QML 创建 C++ 模型的推荐方法是:

  1. 继承 QAbstractListModel(或其他)以创建您的自定义模型。
  2. 重载 rowCount()
  3. 定义您自己的数据角色。

例如:

enum DataRoles {
    Name = Qt::UserRole + 1,
    Description,
    CustomData
};

...


QHash<int, QByteArray> TestList::roleNames() const
{
    QHash<int, QByteArray> res;
    res[static_cast<int>(DataRoles::Name)] = "name";
    res[static_cast<int>(DataRoles::Description)] = "description";
    res[static_cast<int>(DataRoles::CustomData)] = "customData";

    return res;
}
  1. 在重载的data()成员函数中返回相应的数据。

例如:

QVariant TestList::data(const QModelIndex & index, int role) const
{
    QVariant result = QVariant();

    if ( index.isValid() == true ) {
        EntityPtr entityPtr = entities_.at(index.row());

        switch (role) {
        case DataRoles::Name:
            result = entityPtr->name();
            break;
        case DataRoles::Description:
            result = entityPtr->description();
            break;
        case DataRoles::CustomData:
            result = entityPtr->customData();
            break;
        }
    }

    return result;
}

然后,在 QML 上下文中注册您的模型实例后,您可以按名称访问 ListView 委托(delegate)中的实体字段,该名称在 rolesNames() 中定义,例如:

ListView {
    model: yourModelInstance
    ...
    delegate: Item {
        ...
        Text {
            text: name // access DataRoles::Name
        }
        ...
    }
}

IMO,这个实现很好,但是当涉及到从 C++ 端更改属性时,您应该在每次实体属性更改时调用 QAbstractListView 的 dataChaged() 信号.

我希望能够自动通知 View 有关更改,例如当我调用 entity->setName() 时。

我的想法是只注册一个数据角色,例如“对象”将返回整个 QObject,它将具有 Q_PROPERTY,然后从 qml 中访问它,如:

Text {
    text: object.name //access `name` Q_PROPERTY of the object
}

这样,如果 setter 发出正确的信号,在 Q_PROPERTY 声明中注册,QML 端将自动通知有关设置新值的更改。

所以问题是,这是否是实现我目标的好方法,因为正如我上面所说,感觉有点不自然,而 Qt 库可以很好地表明你做错了什么做错事很难(不自然)。

编辑:

按照评论中的要求,我制作了一个小型 Qt 示例应用程序来展示我想要实现的目标。

git 仓库 - https://github.com/shtemberko/SO_question_temp

最佳答案

我认为您需要在 Entity 中为每个属性提供一个 propertyChanged 信号。然后将 propertyChanged 链接到 dataChanged 信号。当您设置名称或设置位置时,发出 propertyChanged 信号。

关于c++ - 为 QML 的 ListView 公开 QObjects 的 QAbstractListModel。好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35797732/

相关文章:

c++ - 更改对象并在同一表达式中使用它但子表达式由逗号运算符分隔是否是未定义的行为?

c++ - 如何将 GSL 与 C++11 和新的 STL 一起使用?

java - Spring - 在 Controller 中检查路径变量是否为空

c++ - 遍历文件夹中的所有文件以继续执行脚本

c++ - Armadillo 和 C++ - 使用二维数组进行矩阵初始化

c++ - Qt C++ 静态 thread_local QNetworkAccessManager 是线程应用程序的好选择吗?

c++ - 我应该在 Qt 中尽可能多地使用信号/插槽吗?

c++ - 如何返回 Qt 的 main ?

java - Spring MVC中如何使用延迟加载

asp.net-mvc - 什么是好的ASP.NET MVC详细错误页面示例