QML的学习与应用:读取本地文件夹下的文件并通过列表显示 您所在的位置:网站首页 文件夹全部列表显示 QML的学习与应用:读取本地文件夹下的文件并通过列表显示

QML的学习与应用:读取本地文件夹下的文件并通过列表显示

2024-03-04 05:57| 来源: 网络整理| 查看: 265

QML的学习与应用:读取本地文件夹下的文件并通过列表显示

最近的数据库课设准备做一个音乐播放器,以QML/QT为构架,边学边做在CSDN上做些笔记。

目前尝试实现本地音乐播放功能中读取本地文件夹下MP3文件并显示的功能,先直接上效果图。

选择了某一文件并通过模型/视图构架进行了显示 选择了一个没有合适文件的目录会显示出提示用户进行选择的按钮 在这里插入图片描述 整个界面使用了QML进行编写,笔者在这个功能上花了比较多的时间,所以先写这个内容,之后有时间把之前的一些内容补上来。

所涉及到的内容 1.模型/视图构架 2.自定义模型类 3.QML与C++交互 4.QML中信号与槽 5.Qt当中读写文件 6.Qt当中遍历文件夹

实现功能的思路大致是自定义一个模型类,其中存储了自定义的音乐类来表示文件夹内的音乐文件信息。将得到的模型类绑定到ListView上并且自定义一个委托去显示。由于笔者这里是通过Loader来进行中间页面的切换的,所以每次载入页面时,根据本地的一个.dat文件中的本地音乐目录信息,来更新显示列表。并且下次再打开播放器的时候可以根据上次设置的音乐文件目录来显示列表。大致是这样的思路,接下来给出一些细节。

模型/视图构架

简单来说就是数据通过模型来存储,通过委托去设置如何显示数据,在视图上绑定模型与委托去显示数据,从而得到数据与显示的分离。QT中的模型/视图构架也是MVC设计模式的一种延伸。 QML当中提供了ListView,TreeView,TableView这三个视图,这里是直接使用了ListView这个视图,使用的方式大致如下:

ListView{ id:l_view model:m_model//自定义的模型对象 focus:true delegate:Button{ //需要注意这里的index与model的index是不一样的使用,要使用listview自带的index property string btn_color anchors.left:parent.left anchors.right: parent.right height: 30 background: Rectangle{ id:btn_bck color:btn_color=(index%2==0?"white":"#f2f5ff") //根据序号的奇偶显示不同的颜色 } Row{ anchors.left:parent.left anchors.leftMargin: 10 anchors.verticalCenter: parent.verticalCenter spacing: 10 Text{//可以直接设置Text的大小来保障文本长度不越界 anchors.verticalCenter: parent.verticalCenter text:lview.model.name(index)//在切换目录时如果切换目录不含音乐则虽然模型是空的, //但是view的index是不会改变的,会造成越界问题,通过槽函数将visible设置为false解决这个问题 font.pointSize: 10 } } MouseArea{//鼠标移上列表中的项颜色会发生变化 anchors.fill: parent hoverEnabled: true onEntered: { btn_bck.color="#e6e6f0" } onExited: { btn_bck.color=btn_color } onClicked: { console.log(index) console.log(lview.currentIndex) } } //每创建一个列表项就更新model中的当前项 Component.onCompleted: { console.log(index) lview.model.setcuritem(index,this) } } }

QML中同样提供了ListView默认用的ListModel模型可以在其中设置ListElement(这是一个字典里面存储键值对)来设置所使用的数据,但是这里我用不到就不多说了。

自定义模型类

之前的模型/视图构架说了要将模型绑定到视图上,但是默认的模型很多时候不能满足我们的需求,只能自定义模型。这里因为是绑定到ListView上,所以我们自定义的模型是继承自QAbstractListModel,去自定义一个ListModel。 这里先给出我们自定义的一个音乐类,在Model当中存的是这个类。

#ifndef MUSIC_H #define MUSIC_H #include #include class Music:public QObject//我这里偷懒了就通过一个.h去写这个类了,最好不要这样。。。 { Q_OBJECT Q_PROPERTY(QString Name READ Name) //如果想要在QML中直接使用一个属性必须定义成Q_PROPERTY,常用设置READ,WRITE,NOTIFY属性 private: QString name; QString writer; QString time; QString album; public: Music(const QString Name="",const QString Writer="",const QString Time="",const QString Album="",QObject* parent=nullptr):QObject(parent),name(Name),writer(Writer),time(Time),album(Album) {}//因为要存在vector中,所以默认constructor是不能少的 //这里需要我显示地定义复制与赋值构造函数,这两个函数一般用来处理深度/浅度赋值的问题 Music(const Music& music) { this->name=music.Name(); this->writer=music.Writer(); this->time=music.Time(); this->album=music.Album(); } Music operator=(const Music& music) { return music; } QString Name() const { return name; } QString Writer() const//表示不能对该成员内部的变量做修改 { return writer; } QString Time()const { return time; } QString Album()const { return album; } QVariant cur;//表示当前的model组件,因为是会根据外面的值进行改变的,所以是public ~Music() {} }; #endif // MUSIC_H

实现QAbstractListModel必须要实现以下三个虚函数,并且在自定义的模型类中给出用于存储数据的数据结构。

int rowCount(const QModelIndex& parent=QModelIndex())//用来给出模型中项的个数 QVarient data(cosnt QModelIndex& index,int role=Qt::QDisplayRole) const//返回相应的数据 QHash roleNames() const//为了在QML中通过别名来使用数据

除了这三个函数之外,还需要给出一些常用的函数比如添加数据,删除数据,等等。接下来给出全部代码。使用模型类的时候有一些问题,虽然能够实现,但没有按照很标准的做法去做,如果有大佬知道的话,也希望能帮我指出,这里先谢谢啦

#ifndef MUSIC_MODEL_H #define MUSIC_MODEL_H #include #include #include #include #include"music.h" class Music_Model : public QAbstractListModel //自定义数据模型,需要自己给出所存储模型的数据类型 { Q_OBJECT Q_PROPERTY(int count READ count NOTIFY countchange)//因为要在QML中使用这个属性 private: QVector music_vct;//使用vector去存储数据 int internel_index=-1;//内部index用来处理排序以及显示的问题 signals: void countchange();//当前模型更新时发射这个信号 void cur_change(int index);//当前模型选项改变时发射这个信号 public: //这个枚举相当于定义数据的别名 enum datatype{ type1=1, type2, type3, type4, type5 }; Music_Model(QObject *parent=nullptr); Q_INVOKABLE void add_data(const QString name,const QString writer,const QString album,const QString time); Q_INVOKABLE void remove_data(int index); Q_INVOKABLE void clear_model(); Q_INVOKABLE int count()const; void Add(Music &music); int rowCount(const QModelIndex &parent = QModelIndex() ) const {//一定要实现的虚函数1 Q_UNUSED(parent); return music_vct.size(); } QVariant data(const QModelIndex &index,int role=Qt::DisplayRole)const; //一定要实现的虚函数2 QHash roleNames()const; //一定要实现的虚函数3,如果要在QML中使用模型那么一定要重写这个函数 Q_INVOKABLE void setcuritem(int index,QVariant j) { internel_index=index; emit cur_change(index); music_vct[index].cur=j; } //因为QML中没办法正常使用Music类,所以试着直接返回QString试试,讲道理最好不要这么做 Q_INVOKABLE QString name(int index); ~Music_Model(){} }; #endif // MUSIC_MODEL_H

以下是.cpp文件

#include "music_model.h" #include Music_Model::Music_Model(QObject* parent):QAbstractListModel (parent) { //注意凡是在QT中使用的组件/模型类都要设置其父亲 } void Music_Model::Add(Music &music) { emit countchange(); beginInsertRows(QModelIndex(),count(),count()); //注意在对自定义模型插入前必须要先给出这个函数 //第二与三个参数表示插入后的数据是第几行都是最后一行则表示都是插在最后,换句话说这里是给出插入位置, //因为一直插入在最后一行,所以下标给vector现在的范围 music_vct.push_back(music); endInsertRows(); //对行/列进行插入必须在上下文中进行,上下文范围限定函数是BeginInsertRows( } void Music_Model::clear_model() { internel_index=-1; emit countchange(); beginRemoveRows(QModelIndex(),0,music_vct.size()-1);//注意这里删除范围是指下标范围的闭区间,否则会越界 music_vct.clear(); endRemoveRows(); //删除通插入要在上下文中进行 } void Music_Model::add_data(const QString name,const QString writer,const QString album,const QString time) { emit countchange(); Music music(name,writer,album,time); //这里的添加数据一定是末尾添加 Add(music); } void Music_Model::remove_data(int index) { emit countchange(); beginRemoveRows(QModelIndex(),index,index);//后两个参数的含义与插入时的相同 music_vct.erase(music_vct.begin()+index); endRemoveRows(); } int Music_Model::count()const { return music_vct.size(); } /*得到相应索引下的数据 这里大致说一下QVariant,这个东西相当于集合类型, 可以存多种QT基本类型,并且提供了相互转化的函数*/ QVariant Music_Model::data(const QModelIndex &index,int role)const { if (index.row() < 0 || index.row() >= music_vct.size()) { return QVariant(); } qDebug()


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有