# 更复杂的数据(More Complex Data) 实际工作中使用的模型数据通常比较复杂。所以需要自定义一些角色枚举方便视图通过属性查找数据。例如模型提供颜色数据不仅只是16进制字符串,在QML中也可以是来自HSV颜色模型的色调,饱和度和亮度,以“model.hue”,“model.saturation”和“model.brightness”作为参数。 ``` #ifndef ROLEENTRYMODEL_H #define ROLEENTRYMODEL_H #include #include class RoleEntryModel : public QAbstractListModel { Q_OBJECT public: // Define the role names to be used enum RoleNames { NameRole = Qt::UserRole, HueRole = Qt::UserRole+2, SaturationRole = Qt::UserRole+3, BrightnessRole = Qt::UserRole+4 }; explicit RoleEntryModel(QObject *parent = 0); ~RoleEntryModel(); // QAbstractItemModel interface public: virtual int rowCount(const QModelIndex &parent) const override; virtual QVariant data(const QModelIndex &index, int role) const override; protected: // return the roles mapping to be used by QML virtual QHash roleNames() const override; private: QList m_data; QHash m_roleNames; }; #endif // ROLEENTRYMODEL_H ``` 在头文件中,我们为QML添加了数据角色枚举的映射。当QML尝试访问一个模型中的属性时(例如“model.name”),链表视图将会在映射中查询“name”然后向模型申请使用```NameRole```角色枚举的数据。用户在定义角色枚举时应该从```Qt::UserRole```开始,并且对于每个模型需要保证唯一。 ``` #include "roleentrymodel.h" RoleEntryModel::RoleEntryModel(QObject *parent) : QAbstractListModel(parent) { // Set names to the role name hash container (QHash) // model.name, model.hue, model.saturation, model.brightness m_roleNames[NameRole] = "name"; m_roleNames[HueRole] = "hue"; m_roleNames[SaturationRole] = "saturation"; m_roleNames[BrightnessRole] = "brightness"; // Append the color names as QColor to the data list (QList) for(const QString& name : QColor::colorNames()) { m_data.append(QColor(name)); } } RoleEntryModel::~RoleEntryModel() { } int RoleEntryModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_data.count(); } QVariant RoleEntryModel::data(const QModelIndex &index, int role) const { int row = index.row(); if(row < 0 || row >= m_data.count()) { return QVariant(); } const QColor& color = m_data.at(row); qDebug() << row << role << color; switch(role) { case NameRole: // return the color name as hex string (model.name) return color.name(); case HueRole: // return the hue of the color (model.hue) return color.hueF(); case SaturationRole: // return the saturation of the color (model.saturation) return color.saturationF(); case BrightnessRole: // return the brightness of the color (model.brightness) return color.lightnessF(); } return QVariant(); } QHash RoleEntryModel::roleNames() const { return m_roleNames; } ``` 现在实现只是改变了两个地方。首先是初始化。我们使用```QColor```数据类型初始化数据链表。此外我们还定义了我们自己的角色名称映射实现QML的访问。这个映射将在后面的```::roleNames```函数中返回。 第二个变化是在```::data```函数中。我们确保能够覆盖到其它的角色枚举(例如色调,饱和度,亮度)。没有可以从颜色中获取SVG名称的方法,由于一个颜色可以替代任何颜色,但SVG名称是受限的。所以我们忽略掉这点。我们需要创建一个结构体```{ QColor, QString }```来存储名称,这样可以鉴别已被命名的颜色。 在注册类型完成后,我们可以使用模型了,可以将它的条目显示在我们的用户界面中。 ``` ListView { id: view anchors.fill: parent model: RoleEntryModel {} focus: true delegate: ListDelegate { text: 'hsv(' + Number(model.hue).toFixed(2) + ',' + Number(model.saturation).toFixed() + ',' + Number(model.brightness).toFixed() + ')' color: model.name } highlight: ListHighlight { } } ``` 我们将返回的类型转换为JS数字类型,这样可以使用定点标记来格式化数字。代码中应当避免直接调用数字(例如```model.saturation.toFixed(2)```)。选择哪种格式取决于你的输入数据。