qml----Model/View入门(五)C++继承实现xmllistmodel

  上一节我们直接用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();
}
原文地址:https://www.cnblogs.com/SaveDictator/p/8244247.html