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

时间:2016-03-04 13:48:57

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

所以我有这样的想法,即使用Q_PROPERTY的QObjects而不是QAbstractListModel的角色名称,以便将需要通知的属性暴露给QML。

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

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

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

    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()成员函数中返回相应的数据。
    2. e.g:

      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委托中的实体字段,在rolesNames()中定义,例如:

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

      IMO,这个实现都很好,但是当涉及到从C ++方面更改属性时,应该在实体属性的每次更改时调用QAbstractListView的dataChaged()信号。 / p>

      我希望能够自动通知有关更改的信息,例如当我打电话给entity->setName() 时。

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

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

      这样,如果setters将发出正确的信号,在Q_PROPERTY声明中注册,QML端将自动通知设置新值的变化。

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

      修改

      正如评论中所要求的,我已经制作了一个小型的Qt示例应用程序,展示了我想要实现的目标。

      git repo - https://github.com/shtemberko/SO_question_temp

1 个答案:

答案 0 :(得分:0)

我认为你需要在每个属性的Entity中使用propertyChanged信号。然后将propertyChanged链接到dataChanged信号。当你设置name或setPosition时,发出propertyChanged signal。