IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> (十)ListView使用C++model -> 正文阅读

[C++知识库](十)ListView使用C++model

C++实现QML可用的Model

ListView可以使用C++语言定义的Model,可以从QAbstractItemModel或者QAbstractListModel继承来实现自己的Model类。最简单的实现,只需要重写rowCount()、data()、rowNames()这三个方法。rowCount()返回Model中的数据条目个数,data(const QModelIndex& index, int role)用来获取某一行、某个角色对应的数据,QModelIndex代表Model中所存放数据的索引,它通过行列位置来唯一确定一个数据,一个数据条目可能有多个role,比如用于显示的DisplayRole,用于鼠标悬停提示的ToolTipRole,还可以用户自定义的role。
对于Qt Quick中的ListView,Delegate通过role-name来访问Model中的数据,当我们在QML中写下Text{text:desc;}这样的Delegate时,意味着将名字为desc的role对应的数据赋值给Text对象的text属性。如何从desc找到实际的数据?这就要依赖rowNames()函数,QHash<int,QBythArray> roleNames() const 返回一个哈希表,将role与rolename关联起来,当QML中提供role-name时,那么就可以反查到role,进而以查到的role来调用data()方法,就可以获取到实际的数据。

#ifndef VIDEOLISTMODEL_H
#define VIDEOLISTMODEL_H

#include<QAbstractListModel>
class VideoListModelPrivate;
class VideoListModel:public QAbstractListModel
{
    Q_OBJECT
    Q_PROPERTY(QString source READ source WRITE setSource)
public:
    VideoListModel(QObject* parent = nullptr);
    ~VideoListModel();
    int rowCount(const QModelIndex &parent) const override;
    QVariant data(const QModelIndex &index, int role) const override;
    QHash<int, QByteArray> roleNames() const override;
    QString source() const;
    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 // VIDEOLISTMODEL_H
#include "videolistmodel.h"
#include<QXmlStreamReader>
#include<QVector>
#include<QFile>
#include<QDebug>
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");
    }
    ~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(elementName == "video")
                {
                    video = new VideoData();
                    QXmlStreamAttributes attrs = reader.attributes();
                    video->append(attrs.value("name").toString());
                    video->append(attrs.value("date").toString());
                }
                else if(elementName == "attr")
                {
                    video->append(reader.attributes().value("tag").toString());
                    video->append(reader.readElementText());
                }
            }
            else if(reader.isEndElement())
            {
                elementName = reader.name();
                if(elementName == "video")
                {
                    m_videos.append(video);
                    video = 0;
                }
            }
        }
        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();
        }
    }

    QString m_strXmlFile;
    QString m_strError;
    bool m_bError;
    QHash<int, QByteArray> m_roleNames;
    QVector<VideoData*> m_videos;
};


VideoListModel::VideoListModel(QObject* parent):QAbstractListModel(parent),m_dptr(new VideoListModelPrivate)
{
}

VideoListModel::~VideoListModel()
{
    if(m_dptr!=nullptr)
    {
        delete m_dptr;
        m_dptr = nullptr;
    }
}

int VideoListModel::rowCount(const QModelIndex &parent) const
{
    return m_dptr->m_videos.size();
}

QVariant VideoListModel::data(const QModelIndex &index, int role) const
{
    VideoData* d = m_dptr->m_videos[index.row()];
    return d->at(role-Qt::UserRole);
}

QHash<int, QByteArray> VideoListModel::roleNames() const
{
    return m_dptr->m_roleNames;
}

QString VideoListModel::source() const
{
    return m_dptr->m_strXmlFile;
}

void VideoListModel::setSource(const QString &filePath)
{
    m_dptr->m_strXmlFile = filePath;
    reload();
    if(m_dptr->m_bError)
    {
        qDebug() << "VideoListModel,error - " << m_dptr->m_strError;
    }
}

QString VideoListModel::errorString() const
{
    return m_dptr->m_strError;
}

bool VideoListModel::hasError() const
{
    return m_dptr->m_bError;
}

void VideoListModel::reload()
{
    beginResetModel();
    m_dptr->reset();
    m_dptr->load();
    endResetModel();
}

void VideoListModel::remove(int index)
{
    beginRemoveRows(QModelIndex(), index, index);
    delete m_dptr->m_videos.takeAt(index);
    endRemoveRows();
}

主要是重写rowCount,data,roleNmaes这三个方法,rowCount表示ListView有多少行数据,data表示获取每一行每一列的数据,roleNames表示ListView中的role-name。

将model导出到QML中

main.cpp代码如下:不清楚可以参考C++与QML混合编程—在QML中使用C++对象

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml/QtQml>
#include "videolistmodel.h"

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

    qmlRegisterType<VideoListModel>("an.qt.CModel",1,0,"VideoListModel");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    return app.exec();
}

main.qml代码如下:

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import an.qt.CModel 1.0

Window {
    visible: true;
    width: 360;
    height: 400;
    color: "#EEEEEE";
    Component{
        id: videoDelegate;
        Item{
            id: wrapper;
            width: 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;
                width: 80;
                height: 120;
                fillMode: Image.PreserveAspectFit;
            }
            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>";
                    color: wrapper.ListView.isCurrentItem ? "blue" : "black";
                    font.pixelSize: 18;
                    elide: Text.ElideRight;
                }
                Text{
                    text: date;
                    Layout.fillWidth: true;
                    color: wrapper.ListView.isCurrentItem ? "blue" : "black";
                    font.pixelSize: 18;
                    elide: Text.ElideRight;
                }
                Text{
                    text: director_tag+": <font color=\"#0000aa\">" + director + "</font>";
                    Layout.fillWidth: true;
                    color: wrapper.ListView.isCurrentItem ? "blue" : "black";
                    font.pixelSize: 18;
                    elide: Text.ElideRight;
                }
                Text {
                    text: actor_tag+": <font color=\"#0000aa\">" + actor + "</font>";
                    Layout.fillWidth: true;
                    color: wrapper.ListView.isCurrentItem ? "blue" : "black";
                    font.pixelSize: 18;
                    elide: Text.ElideRight;
                }
            }
        }
    }

    ListView{
        id: listView;
        anchors.fill: parent;
        spacing: 4;
        delegate: videoDelegate;
        model: VideoListModel{
            source: "videos.xml";
        }
        focus: true;
        highlight: Rectangle{
            width: parent.width;
            color: "lightblue";
        }
    }


}

video.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<videos>
	<video name="冰雪奇缘" date="2014-11-19">
		<attr tag="导演">詹妮弗李</attr>
		<attr tag="演员">伊迪娜</attr>
	</video>
	<video name="功夫" date="2004-12-23">
		<attr tag="导演">周星驰</attr>
		<attr tag="演员">周星驰</attr>
	</video>
	<video name="小时代" date="2013-6-27">
		<attr tag="导演">郭敬明</attr>
		<attr tag="演员">杨幂</attr>
	</video>
	<video name="倩女幽魂" date="1987-07-18">
		<attr tag="导演">程小东</attr>
		<attr tag="演员">张国荣</attr>
	</video>
</videos>

其实一直都有一个比较奇怪的问题,使用qt总是无法通过编译,而使用vs2015就能通过,现在也没搞清楚原因。
效果如下:
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:26:01  更:2022-05-18 17:28:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:14:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码