上一节我们直接用xmlListModel读取xml文件数据,这一节我们来看怎么用C++来实现它
首先我们自定义头文件vediolistmodel.h,代码如下:
#ifndef VedioListModel_H #define VedioListModel_H #include <QAbstractListModel> class VideoListModelPrivate; class VedioListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QString source READ source WRITE setSource)//导出source属性 public: VedioListModel(QObject* parent = 0); ~VedioListModel(); int rowCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; QHash<int, QByteArray> roleNames() const; QString source(); void setSource(const QString& filePath); Q_INVOKABLE QString errorString() const; Q_INVOKABLE bool hasError() const; Q_INVOKABLE void reload(); Q_INVOKABLE void remove(int index); private: VideoListModelPrivate *m_dptr; }; #endif // VedioListModel_H
然后再看实现文件vediolistmodel.cpp
#include "VedioListModel.h" #include <QXmlStreamReader> #include <QVector> #include <QDebug> #include <QFile> typedef QVector<QString> VideoData; class VideoListModelPrivate { public: VideoListModelPrivate() : m_bError(false) { int role = Qt::UserRole; m_roleNames.insert(role++, "name"); m_roleNames.insert(role++, "date"); m_roleNames.insert(role++, "director_tag"); m_roleNames.insert(role++, "director"); m_roleNames.insert(role++, "actor_tag"); m_roleNames.insert(role++, "actor"); m_roleNames.insert(role++, "rating_tag"); m_roleNames.insert(role++, "rating"); m_roleNames.insert(role++, "desc_tag"); m_roleNames.insert(role++, "desc"); m_roleNames.insert(role++, "img"); m_roleNames.insert(role++, "playpage"); m_roleNames.insert(role++, "playtimes"); } ~VideoListModelPrivate(){clear();} void load(){ QXmlStreamReader reader; QFile file(m_strXmlFile); if(!file.exists()) { m_bError = true; m_strError = "file not found!"; return; } if(!file.open(QFile::ReadOnly)) { m_bError = true; m_strError = file.errorString(); return; } reader.setDevice(&file); QStringRef elementName; VideoData *video; while(!reader.atEnd()) { reader.readNext(); if(reader.isStartElement()) { elementName = reader.name(); if("video" == elementName) { video = new VideoData(); QXmlStreamAttributes attrs = reader.attributes(); video->append(attrs.value("name").toString()); video->append(attrs.value("date").toString()); } else if("attr" == elementName) { video->append(reader.attributes().value("tag").toString()); video->append(reader.readElementText()); } else if("poster" == elementName) { video->append(reader.attributes().value("img").toString()); } else if("page" == elementName) { video->append(reader.attributes().value("link").toString()); } else if("playtimes" == elementName) { video->append(reader.readElementText()); } }// reader is startElement else if(reader.isEndElement()) { elementName = reader.name(); if("video" == elementName) { m_videos.append(video); video = 0; } } }//while is end file.close(); if(reader.hasError()) { m_bError = true; m_strError = reader.errorString(); } } void reset() { m_bError = false; m_strError.clear(); clear(); } void clear() { int count = m_videos.size(); if(count > 0) { for(int i = 0; i < count; i++) delete m_videos.at(i); m_videos.clear(); } } public: QString m_strXmlFile; QString m_strError; bool m_bError; QHash<int, QByteArray> m_roleNames; QVector<VideoData*> m_videos; }; VedioListModel::VedioListModel(QObject* parent) :QAbstractListModel(parent), m_dptr(new VideoListModelPrivate) { } VedioListModel::~VedioListModel() { delete m_dptr; } int VedioListModel::rowCount(const QModelIndex &parent) const { return m_dptr->m_videos.size(); } QVariant VedioListModel::data(const QModelIndex &index, int role) const { VideoData *d = m_dptr->m_videos[index.row()]; return d->at(role - Qt::UserRole); } QHash<int, QByteArray> VedioListModel::roleNames() const { return m_dptr->m_roleNames; } QString VedioListModel::source() { return m_dptr->m_strXmlFile; } void VedioListModel::setSource(const QString &filePath) { m_dptr->m_strXmlFile = filePath; reload(); if(m_dptr->m_bError) qDebug()<<"VideoListMode , error-"<<m_dptr->m_strError; } QString VedioListModel::errorString() const { return m_dptr->m_strError; } bool VedioListModel::hasError() const { return m_dptr->m_bError; } void VedioListModel::reload() { beginResetModel(); m_dptr->reset(); m_dptr->load(); endResetModel(); } void VedioListModel::remove(int index) { beginRemoveRows(QModelIndex(), index, index); delete m_dptr->m_videos.takeAt(index); endRemoveRows(); }
再来看main.qml文件
import QtQuick 2.2 import QtQuick.Window 2.1 import QtQuick.Layouts 1.1 import an.qt.CModel 1.0 Window{ visible: true 360 height: 400 color: "#EEEEEE" Component{ id: videoDelegate Item { id: wrapper parent.width height: 120 MouseArea{ anchors.fill: parent onClicked: wrapper.ListView.view.currentIndex = index } Image{ id: poster anchors.left: parent.left anchors.top: parent.top source: img 80 height: 120 fillMode: Image.PreserveAspectFit }//image is end ColumnLayout{ anchors.left: poster.right anchors.leftMargin: 4 anchors.right: wrapper.right anchors.top: poster.top height: parent.height spacing: 2 Text{ Layout.fillWidth: true text: "<b>" + name + "</b>(" + rating + "," + playtimes + ")"; color: wrapper.ListView.isCurrentItem ? "blue" : "black" font.pixelSize: 18 elide: Text.ElideRight } Text{ Layout.fillWidth: true text: date color: wrapper.ListView.isCurrentItem ? "blue" : "black" font.pixelSize: 18 elide: Text.ElideRight } Text{ Layout.fillWidth: true text: director_tag + ":<font color =#0000aa">" + director + "</font>" color: wrapper.ListView.isCurrentItem ? "blue" : "black" font.pixelSize: 18 elide: Text.ElideRight } Text{ Layout.fillWidth: trues text: actor_tag + ":<font color=#0000aa">" + actor + "</font>" color: wrapper.ListView.isCurrentItem ? "blue" : "black" font.pixelSize: 18 elide: Text.ElideRight } Text{ Layout.fillWidth: true Layout.fillHeight: true text: desc color: wrapper.ListView.isCurrentItem ? "blue" : "black" font.pixelSize: 16 wrapMode: Text.wrapMode maximumLineCount: 2 elide: Text.ElideRight } }//ColumnLayout is end } }//videoDelegate is end ListView{ id: listView anchors.fill: parent spacing: 4 delegate: videoDelegate model: VedioListModel{source: ":/videos.xml";} focus: true highlight: Rectangle{ color: "lightblue" } } }
最后是C++类的注册,在main.cpp中
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml/QtQml> #include <QQuickView> #include "vediolistmodel.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<VedioListModel>("an.qt.CModel", 1, 0, "VedioListModel"); // QQuickView view; // view.setResizeMode(QQuickView::SizeRootObjectToView); // view.setSource(QUrl(QStringLiteral("qrc:/main.qml"))); // view.show(); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec(); }