Qt 之 Qml 中Data Models (ListModel等)

概述

在使用qml的过程中,ListView应该是最常用的视图了,从MVC(model view control) 到现在的MVD(model view delegete),model是其中的数据载体,为视图提供数据来源,也是最核心的环节。
qml 中提供了多种Data model,本文将对其中常见的做个总结。

QML Data Models

ListModel

Properties
count : int
dynamicRoles : bool //默认是false

Methods
append(jsobject dict)
clear()
object get(int index)
insert(int index, jsobject dict)
move(int from, int to, int n)
remove(int index, int count)
set(int index, jsobject dict)
setProperty(int index, string property, variant value)
sync()

从属性和方法的名字基本可以知道其作用
ListModel 举例

ListModel {
    id: fruitModel
    ListElement {name: "Apple" cost: 2.45}
    ListElement {name: "Orange"cost: 3.25}
    ListElement {name: "Banana"cost: 1.95}
}

模型有两个role,name 和cost

Rectangle {
    width: 200; height: 200

    ListModel {
        id: fruitModel
        ...
    }

    Component {
        id: fruitDelegate
        Row {
            spacing: 10
            Text { text: name }
            Text { text: '$' + cost }
        }
    }

    ListView {
        anchors.fill: parent
        model: fruitModel
        delegate: fruitDelegate
    }
}

roles角色有可能包含列表数据。在以下示例中,我们创建一个列表的水果属性:

ListModel {
    id: fruitModel

    ListElement {
        name: "Apple"
        cost: 2.45
        attributes: [
            ListElement { description: "Core" },
            ListElement { description: "Deciduous" }
        ]
    }
    ListElement {
        name: "Orange"
        cost: 3.25
        attributes: [
            ListElement { description: "Citrus" }
        ]
    }
    ListElement {
        name: "Banana"
        cost: 1.95
        attributes: [
            ListElement { description: "Tropical" },
            ListElement { description: "Seedless" }
        ]
    }
}

创建上述model的代理

Component {
    id: fruitDelegate
    Item {
        width: 200; height: 50
        Text { id: nameField; text: name }
        Text { text: '$' + cost; anchors.left: nameField.right }
        Row {
            anchors.top: nameField.bottom
            spacing: 5
            Text { text: "Attributes:" }
            Repeater {
                model: attributes
                Text { text: description }
            }
        }
    }
}

实现效果,如图
水果属性
修改ListModel
可以通过 clear(), append(), set(), insert() 和 setProperty() 这些方法;

 Component {
        id: fruitDelegate
        Item {
            width: 200; height: 50
            Text { text: name }
            Text { text: '$' + cost; anchors.right: parent.right }

            // Double the price when clicked.
            MouseArea {
                anchors.fill: parent
                onClicked: fruitModel.setProperty(index, "cost", cost * 2) //价格x2
            }
        }
    }
Component.onCompleted: {
    fruitModel.append({"cost": 5.95, "name":"Jackfruit"});
    console.log(fruitModel.get(0).cost);
    fruitModel.get(0).cost = 10.95;
}
fruitModel.append(..., "attributes":
    [{"name":"spikes","value":"7mm"},
     {"name":"color","value":"green"}]);
fruitModel.get(0).attributes.get(1).value; // == "green"

fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
fruitModel.move(0, fruitModel.count - 3, 3)
fruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
fruitModel.setProperty(3, "cost", 5.95)

XmlListModel

XmlListModel允许从XML数据源模型的建设。通过指定的角色XmlRole类型。需要导入的类型。
 
import QtQuick。XmlListModel 2.0
下面的模型有三个角色,title、link和description:

  XmlListModel {
       id: feedModel
       source: "http://rss.news.yahoo.com/rss/oceania"
       query: "/rss/channel/item"
       XmlRole { name: "title"; query: "title/string()" }
       XmlRole { name: "link"; query: "link/string()" }
       XmlRole { name: "description"; query: "description/string()" }
  }

ObjectModel

ObjectModel可以用QML items ,比如Rectanle,Text作为模型。这种模型包括了数据和代理,所以不需要额外提供delegate

  import QtQuick 2.0
  import QtQml.Models 2.1

  Rectangle {
      ObjectModel {
          id: itemModel
          Rectangle { height: 30; width: 80; color: "red" }
          Rectangle { height: 30; width: 80; color: "green" }
          Rectangle { height: 30; width: 80; color: "blue" }
      }

      ListView {
          anchors.fill: parent
          model: itemModel
      }
  }
  VisualItemModel {
      id: itemModel
      Rectangle { height: 30; width: 80; color: "red" }
      Rectangle { height: 30; width: 80; color: "green" }
      Rectangle { height: 30; width: 80; color: "blue" }
  }
 
  ListView {
      anchors.fill: parent
      model: itemModel
  }

整数模型

不含任何角色

Item {
      width: 200; height: 250

      Component {
          id: itemDelegate
          Text { text: "I am item number: " + index }
      }

      ListView {
          anchors.fill: parent
          model: 5
          delegate: itemDelegate
      }

  }

对象实例作为模型

对象的属性来作为模型的role,比如下面的myText 的属性text 和 color

Rectangle {
      width: 200; height: 250

      Text {
          id: myText
          text: "Hello"
          color: "#dd44ee"
      }

      Component {
          id: myDelegate
          Text { text: model.color }
      }

      ListView {
          anchors.fill: parent
          anchors.topMargin: 30
          model: myText
          delegate: myDelegate
      }
  }

C++ 数据模型

QStringList

QStringList通过 modelData 来提供数据

 	QStringList dataList;
    dataList.append("Item 1");
    dataList.append("Item 2");
    dataList.append("Item 3");
    dataList.append("Item 4");

    QQuickView view;
    QQmlContext *ctxt = view.rootContext();
    ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
ListView {
      width: 100; height: 100
      model: myModel
      delegate: Rectangle {
          height: 25
          width: 100
          Text { text: modelData }
      }
  }

但需要注意的是,当模型中数据改变时,即QStringList改变,不会自动同步到视图显示,需要我们再一次调用 QDeclarativeContext::setContextProperty() ,重新设定模型

QObjectList-based Model

class myItem : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
public:
    explicit myItem(QObject *parent = nullptr)
    myItem(QString name,QString colo)
    {
        m_name = name;
        m_color = colo;
    }

    QString  name(){return m_name;}
    void setName(QString str){m_name =str; emit nameChanged();}
    QString  color(){return  m_color;}
    void setColor(QString co){m_color = co;emit colorChanged();}

signals:
    void nameChanged();
    void colorChanged();
private:
    QString m_name;
    QString m_color;
};
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    
    QList<QObject*> dataList;
    dataList.append(new myItem("Item 1", "red"));
    dataList.append(new myItem("Item 2", "green"));
    dataList.append(new myItem("Item 3", "blue"));
    dataList.append(new myItem("Item 4", "yellow"));
    
    QQmlApplicationEngine engine;
    QQmlContext *pcont = engine.rootContext();
    pcont->setContextProperty("myModel", QVariant::fromValue(dataList));
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}
import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    ListView {
        width: 100; height: 100
        anchors.fill: parent

        model: myModel
        delegate: Rectangle {
            height: 25
            width: 100
            color: model.modelData.color  //也可以通过model.color
            Text { text: model.modelData.name }  //也可以通过model.name
        }
    }
}

效果:
在这里插入图片描述

继承QAbstractItemModel

QAbstractItemModel还可以自动通知QML视图模型数据改变时。
QAbstractItemModel子类的角色可以被重新实现暴露QML QAbstractItemModel:: roleNames ()。
QML视图模型改变时自动更新。模型必须遵循的标准规则模型更改并通知视图,当模型改变了通过使用QAbstractItemModel:: dataChanged (), QAbstractItemModel: beginInsertRows(),等等
model.h

class Animal
{
public:
    Animal(const QString &type, const QString &size);
    QString type() const;
    QString size() const;
private:
    QString m_type;
    QString m_size;
};

class AnimalModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum AnimalRoles {
        TypeRole = Qt::UserRole + 1,
        SizeRole
    };
    AnimalModel(QObject *parent = 0);
    void addAnimal(const Animal &animal);
    int rowCount(const QModelIndex & parent = QModelIndex()) const;
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
protected:
    QHash<int, QByteArray> roleNames() const;
private:
    QList<Animal> m_animals;
};

model.cpp

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)
{
}

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();
}

QHash<int, QByteArray> AnimalModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[TypeRole] = "type";
    roles[SizeRole] = "size";
    return roles;
}

main.cpp

//![0]
int main(int argc, char ** argv)
{
    QGuiApplication app(argc, argv);

    AnimalModel model;
    model.addAnimal(Animal("Wolf", "Medium"));
    model.addAnimal(Animal("Polar bear", "Large"));
    model.addAnimal(Animal("Quoll", "Small"));

    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    QQmlContext *ctxt = view.rootContext();
    ctxt->setContextProperty("myModel", &model);
//![0]

    view.setSource(QUrl("qrc:view.qml"));
    view.show();

    return app.exec();
}

view.qml

import QtQuick 2.0

//![0]
ListView {
    width: 200; height: 250
    model: myModel
    delegate: Text { text: "Animal: " + type + ", " + size }
}
//![0]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值