qml 结合 QSqlTableModel 动态加载数据 MVC「建议收藏」

效果预览:一、准备好对应的 QSqlTableModel#ifndefLOCALMUSICMODEL_H#defineLOCALMUSICMODEL_H#include<QObject>#include<QSqlTableModel>#include<QMediaPlayer>#include"libzplay.h"usingname…

大家好,又见面了,我是你们的朋友全栈君。

效果预览:

qml 结合 QSqlTableModel 动态加载数据 MVC「建议收藏」

一、准备好对应的 QSqlTableModel

#ifndef LOCALMUSICMODEL_H
#define LOCALMUSICMODEL_H

#include <QObject>
#include <QSqlTableModel>
#include <QMediaPlayer>
#include "libzplay.h"
using namespace libZPlay;

struct songInfo
{
    QString Artist;
    QString title;
    QString album;
    qint32 duration = 0;
    QString path;

};

class LocalMusicModel : public QSqlTableModel
{
    Q_OBJECT
    Q_PROPERTY(int m_musicNum READ musicNum WRITE setMusicNum NOTIFY musicNumChanged)



public:
    explicit LocalMusicModel(QObject *parent = nullptr);
    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
    QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;

    Q_INVOKABLE void reloadMusicRecord(const QString &path);
    int musicNum(){return m_musicNum;}
    void setMusicNum(int val){
        m_musicNum = val;
        emit musicNumChanged();
    }

signals:
    void musicNumChanged();

private:
    void parseMusicInfo(QString path);
    void clearDb();

private:
    ZPlay *player;
    int m_musicNum = 0;

};

#endif // LOCALMUSICMODEL_H

#include "localmusicmodel.h"

#include <QDateTime>
#include <QSqlRecord>
#include <QDebug>
#include <QSqlError>
#include <QSqlQuery>
#include <QDir>


static const char *localMusicTableName = "LocalMusicInfo";

static void createTable()
{
    if (QSqlDatabase::database().tables().contains(localMusicTableName)) {
        // The table already exists; we don't need to do anything.
        return;
    }

    QSqlQuery query;
    QString sql_ = QStringLiteral("CREATE TABLE IF NOT EXISTS [LocalMusicInfo] (         \
                                  [title] VARCHAR2 , \
                                  [singer] VARCHAR2 , \
                                  [album] VARCHAR2 , \
                                  [duration] INTEGER ,\
                                  [path] VARCHAR2 NOT NULL ,          \
                                  UNIQUE([path]) ON CONFLICT REPLACE \
                                  )");


    if (!query.exec(sql_)) {
        qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
    }

    //query.exec("INSERT INTO LocalMusicInfo VALUES('title', 'singer', 'album', 123,'c://')");
}


LocalMusicModel::LocalMusicModel(QObject *parent)
    : QSqlTableModel(parent)
{
    createTable();
    setTable(localMusicTableName);
    /*可以看到这个模型很强大,而且完全脱离了SQL语句,就算你不怎么懂数据库,
     * 也可以利用它进行大部分常用的操作。这个模型提供了缓冲区,可以将所有修改先保存到model中,
     * 只有当我们执行提交修改后,才会真正写入数据库。当然这也是因为我们在最开始设置了它的保存策略:
    submitAll();   revertAll();*/
    setEditStrategy(QSqlTableModel::OnManualSubmit);
    select();
    player = CreateZPlay();

    setMusicNum(this->rowCount());
}

QVariant LocalMusicModel::data(const QModelIndex &index, int role) const
{
    if (role < Qt::UserRole)
            return QSqlTableModel::data(index, role);

    const QSqlRecord sqlRecord = record(index.row());

    //qDebug() << sqlRecord.value(role - Qt::UserRole);

    switch (role) {
    case Qt::UserRole:
        if(sqlRecord.value(0).toString().isEmpty())
        {
            QString path = sqlRecord.value(role - Qt::UserRole + 4).toString();
            path =  path.right(path.lastIndexOf('/'));
            path.chop(4);
            return  path.simplified();
        }
        break;
    case Qt::UserRole+1:
        if(sqlRecord.value(1).toString().isEmpty())
            return tr("未知歌手");
        break;
    case Qt::UserRole+2:
        if(sqlRecord.value(2).toString().isEmpty())
            return tr("未知专辑");
        break;
    case Qt::UserRole+3:
        int time = sqlRecord.value(3).toInt();
        return QString("%1:%2").arg(time/60).arg(time%60,2,10,QChar('0'));
    }
    return sqlRecord.value(role - Qt::UserRole);
}

QHash<int, QByteArray> LocalMusicModel::roleNames() const
{
    QHash<int, QByteArray> names;
    names[Qt::UserRole] = "title";
    names[Qt::UserRole + 1] = "singer";
    names[Qt::UserRole + 2] = "album";
    names[Qt::UserRole + 3] = "duration";
    names[Qt::UserRole + 4] = "path";
    return names;
}

void LocalMusicModel::reloadMusicRecord(const QString &path_)
{
    parseMusicInfo(path_);
}

//获取指定目录下所有歌曲信息
void LocalMusicModel::parseMusicInfo(QString path)
{
    QList<songInfo> songRecords;
    QStringList dirList=path.split(",");
    QString temp;
    foreach (temp, dirList) {
        temp=temp.right(temp.length()-8);
        QDir dir(temp);
        dir.setNameFilters(QStringList() << "*.mp3" << "*.flac" << "*.wav");
        QFileInfoList fileList=dir.entryInfoList();
        QFileInfo fileInfo;

        foreach (fileInfo, fileList) {
            TID3InfoEx id3_info;
            //如果直接使用LoadFileID3Ex函数,会得不到时长信息
            if(player->OpenFile((const char*) fileInfo.absoluteFilePath().toLocal8Bit(),sfAutodetect))
                if(player->LoadID3Ex(&id3_info,1))
                {
                    songInfo tempSongInfo;
                    tempSongInfo.title = QString::fromLocal8Bit(id3_info.Title);    //音乐标题
                    tempSongInfo.Artist = QString::fromLocal8Bit(id3_info.Artist);  //歌手
                    tempSongInfo.path = fileInfo.absoluteFilePath();                //路径
                    tempSongInfo.album = QString::fromLocal8Bit(id3_info.Album);    //专辑
                    // get stream info,获取时长信息
                    TStreamInfo pInfo;
                    player->GetStreamInfo(&pInfo);
                    tempSongInfo.duration =pInfo.Length.sec;
                    songRecords.append(tempSongInfo);
                }
                else
                {
                    qDebug() << QString("No ID3 data:%1\r\n\r\n").arg(QString::fromLocal8Bit(player->GetError()));
                }
            else
            {
                qDebug() << "LoadID3Ex faild";
            }
        }
    }

    clearDb();

    QSqlRecord newRecord = record();
    for(auto songItem : songRecords)
    {
        newRecord.setValue("title", songItem.title);
        newRecord.setValue("singer", songItem.Artist);
        newRecord.setValue("album", songItem.album);
        newRecord.setValue("duration", songItem.duration);
        newRecord.setValue("path", songItem.path);

        if (!insertRecord(rowCount(), newRecord)) {
            qWarning() << "Failed to send message:" << lastError().text();
            return;
        }
    }

    submitAll();//提交数据库
    setMusicNum(songRecords.size());
}

void LocalMusicModel::clearDb()
{
    if (!QSqlDatabase::database().tables().contains(localMusicTableName)) {
        createTable();
    }

    QSqlQuery query;
    QString sql_ = QStringLiteral("delete from [LocalMusicInfo]");

    if (!query.exec(sql_)) {
        qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
    }
    qDebug() << "clear table ok";
}

重点是

QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;

QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;

给你需要的数据设置好role,方便qml进行调用。

二、qml调用

main.cpp

qmlRegisterType<LocalMusicModel>("io.qt.CloudMusic", 1, 0, "LocalMusicModel");

qml:

import io.qt.CloudMusic 1.0

LocalMusicModel{
 
 id:localmusic;}
            TableView{
                id: tableview
                anchors.fill: parent
                visible: localmusic.m_musicNum >0
                backgroundVisible: false;
                frameVisible: false;
                //itemDelegate: StandardTabelItemDelegate{} //代理
                //headerDelegate: headerDele;  //表头委托
                //rowDelegate: rowDele;   //行委托
                model: localmusic

                TableViewColumn {
                          role: "title"
                          title: qsTr("标题")
                          width: 300
                      }
                TableViewColumn {
                          role: "singer"
                          title: qsTr("歌手")
                          width: 300
                      }
                TableViewColumn {
                          role: "album"
                          title: qsTr("专辑")
                          width: 300
                      }
                TableViewColumn {
                          role: "duration"
                          title: qsTr("时长")
                          width: 300
                      }
            }

代理待后面继续完善

qml之从零开始编写网易云音乐目录

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/127739.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • DM368开发 — 常用指令演示

    DM368开发 — 常用指令演示查看CPU信息:root@dm368-evm:/proc#catcpuinfo Processor   :ARM926EJ-Srev5(v5l)BogoMIPS    :147.86Features    :swphalfthumbfastmultedspjava CPUimplementer:0x41CPUarch

    2022年8月13日
    11
  • 打印纸张尺寸换算_各种打印纸的尺寸是多少?「建议收藏」

    打印纸张尺寸换算_各种打印纸的尺寸是多少?「建议收藏」展开全部常用打印纸尺寸为:A4(16k)297mm×210mm;A5(32k)210mm×148mm;A6(64k)144mm×105mm;A3(8k)420mm×297mm。按照尺寸的大小,通常62616964757a686964616fe4b893e5b19e31333431343738分三种类型:大型开本、中型开本和小型开本。以787×1092的纸来说,12开以上为大型开本,16~36开为…

    2022年6月20日
    66
  • python安装cv2模块的方法(python中cv2库)

    python如何安装cv2模块  大家在第一次安装cv2模块的时候可能会犯这样的错误,输入pip(3)installcv2命令后,vc2并没有开始安装,而是返回这样一个错误一个错误:Couldnotfindaversionthatsatisfiestherequirementcv2(fromversions:)Nomatchingdistributionf…

    2022年4月14日
    66
  • 2021Vue.js面试题汇总及答案【全网最全 建议收藏】「建议收藏」

    2021Vue.js面试题汇总及答案【全网最全 建议收藏】「建议收藏」文章目录前言一、Vue.js基本问题1.1.Vue响应式原理1.2.Vue.js的特点1.3.Vue.js双向绑定的原理1.4.Vue中如何监控某个属性值的变化?1.5.Vue.js3.0放弃defineProperty,使用Proxy的原因1.6.Vue2中给data中的对象属性添加一个新的属性时会发生什么?如何解决?前言之前博主有分享过Vue学习由浅到深的文章(Vue学习之从入门到神经)现在Vue学的好的话马内真的不必后端差所以今天博主就汇总下有关Vue的相关面试题

    2022年6月12日
    48
  • adminLte解决iframe高度问题

    adminLte解决iframe高度问题adminLte默认是全局刷新,也就是不存在frame页面,经过修改,可以很容易实现右边内容框用frame实现页面刷新,这样就不需要整个页面全局刷新,点击相应菜单时,只会刷新frame窗口,但是有一个问题就是frame默认高度只有一丁点,百度之后用了自适应也会有各种问题,比如高度只能拉伸不会缩短,在解决的道路上真的是没有一个完美的解决方案,经过自己研究,发现一个非常简单的方法,那就是用js获取wi…

    2022年7月27日
    14
  • e5续订程序_office e5开发者

    e5续订程序_office e5开发者E5调用API续订服务:Microsoft365E5RenewX:功能性:网页访问部分继承于Microsoft365E5RenewWeb并做了部分改进,数据库改进现在支持单用户多运行账号;内核API调用继承于Microsoft365E5RenewPlus;可部署性:支持开放站点部署和私享部署,私享部署不再强制要求配置Https和OAuth平台兼容性:使用Asp.NetCore作为跨平台框架增适用于WindowsLinuxMacOS…

    2022年9月30日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号