如何用QStringList填充listview?

时间:2018-01-31 04:33:06

标签: c++ qt qml

我正在开发一个应用程序,它可以在SD卡中找到所有mp4视频,并将它们列在listview中。使用一个按钮播放列表中的所有视频,或单击其中一个视频列表即可播放该视频。

我不知道如何实现C ++中的QStringlist与QML中的folderModel之间的链接。也许它应该使用另一种方法用QStringlist填充listview。我已经在C ++端实现了mp4文件的搜索部分,但是不知道如何使用存储mp4视频文件路径的QStringlist填充listview。请帮忙。

源代码:

filemodel.cpp

#ifndef FILEMODEL_H
#define FILEMODEL_H

#include <QObject>
#include <QStringList>
#include <QDirIterator>
#include <QString>

class MyObject : public QObject{
   Q_OBJECT
public:
    explicit MyObject (QObject* parent = 0) : QObject(parent) {}
    Q_INVOKABLE QStringList findfile();
};


QStringList MyObject::findfile( ) {
    QStringList all_dirs;
    QDirIterator it(dir, QStringList() << "*.mp4", QDir::Files, QDirIterator::Subdirectories);
    while (it.hasNext()){
        all_dirs << it.next();
    }
}

#endif // FILEMODEL_H

的main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    MyObject obj;
    engine.rootCtontext()->setContextProperty("MyObject", &obj);
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.1
import Qt.labs.folderlistmodel 2.1
import QtMultimedia 5.0
import QtQuick.Controls.Styles 1.4
import Qt.labs.platform 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")        

    SwipeView {
        id: swipeView
        anchors.fill: parent
        currentIndex: tabBar.currentIndex

        Page1 {            
            ListView {
                width: 200; height: 400

                FolderListModel {
                    id: folderModel
                    nameFilters: ["*.mp4"]
                }

                Component {
                    id: fileDelegate
                    Text { text: fileName }
                }

                model: folderModel
                delegate: fileDelegate
            }

            Button {
                id: button

                width: parent.width
                text: "Play"
                background: Rectangle {
                    implicitHeight: 40
                    border.color: "#26282a"
                    border.width: 2
                    radius: 4
                }
                onClicked:
                {
                    player.source = folderModel.get (0, "fileURL")
                    playTimer.start()
                    player.play()
                    swipeView.setCurrentIndex(1)
                }
            }
        }

        Page {
            MediaPlayer {
                id: player
            }

            VideoOutput {
                    id: video
                    anchors.fill: parent
                    source: player
            }
        }
    }

    function setImageIndex(i)
    {
        index = i;
        if (index >= 0 && index < folderModel.count){
            player.source = folderModel.get (index, "fileURL");
            player.play();
        }
        else{
            player.source = folderModel.get (index, "fileURL");
            player.play();
        }
    }

    Timer {
        id: playTimer
        interval: 2000
        repeat: true
        running: true
        onTriggered: {
            var source_name = player.source;

            if(source_name.toString().indexOf(".mp4")>0){ //processing .mp4
                if (player.status == MediaPlayer.EndOfMedia){
                    if (index + 1 < folderModel.count){
                        setImageIndex(index + 1);
                    }
                    else{
                        index = 0;
                        setImageIndex(index);
                    }
                }
            }
        }
     }

    footer: TabBar {
        id: tabBar
        currentIndex: swipeView.currentIndex
        TabButton {
            text: qsTr("First")
        }
        TabButton {
            text: qsTr("Second")
        }
    }
}

1 个答案:

答案 0 :(得分:3)

如果你想用C ++制作自己的过滤器,你不应该使用FolderListModel,这样做有几种可能性。

  1. 其中一个是为它实现自己的模型,我们创建一个继承自QAbstractListModel的类:
  2. #ifndef FILEMODEL_H
    #define FILEMODEL_H
    
    #include <QAbstractListModel>
    #include <QDirIterator>
    #include <QUrl>
    #include <QMetaType>
    #include <QFuture>
    #include <QtConcurrent>
    
    struct File
    {
        Q_GADGET
        Q_PROPERTY(QString name MEMBER name)
        Q_PROPERTY(QUrl url MEMBER url)
    public:
        QString name;
        QUrl url;
        File(const QString& name=""){
            this->name = QFileInfo(name).fileName();
            this->url = QUrl::fromLocalFile(name);
        }
    };
    Q_DECLARE_METATYPE(File)
    
    class FileModel : public QAbstractListModel
    {
        enum dashBoardRoles {
            NameRole=Qt::UserRole+1,
            URLRole
        };
        Q_OBJECT
        Q_PROPERTY(QString folder READ folder WRITE setFolder NOTIFY folderChanged)
        Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
    public:
        FileModel(QObject *parent=Q_NULLPTR):QAbstractListModel(parent){
        }
    
        Q_INVOKABLE QVariant get(int index){
            return QVariant::fromValue(m_all_dirs[index]);
        }
    
        int rowCount(const QModelIndex &parent=QModelIndex()) const{
            Q_UNUSED(parent)
            return m_all_dirs.count();
        }
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const{
            if(index.row()<0 && index.row()>= rowCount())
                return QVariant();
            File  file = m_all_dirs[index.row()];
            if(role == NameRole)
                return file.name;
            else if(role == URLRole)
                return file.url;
            return QVariant();
        }
    
        QHash<int, QByteArray> roleNames() const {
            QHash <int,QByteArray> roles;
            roles [NameRole]="fileName";
            roles [URLRole]="url";
            return roles;
        }
    
        QString folder() const{
            return mFolder;
        }
    
        void setFolder(const QString &folder)
        {
            if(mFolder == folder)
                return;
            mFolder = folder;
            emit folderChanged();
            findFiles();
        }
    
        QStringList nameFilters() const{
            return mNameFilters;
        }
    
        void setNameFilters(const QStringList &nameFilters){
            if(mNameFilters == nameFilters)
                return;
            mNameFilters = nameFilters;
            emit nameFiltersChanged();
            findFiles();
        }
    
    signals:
        void folderChanged();
        void nameFiltersChanged();
    
    private:
        void findFiles(){
    
            beginResetModel();
            m_all_dirs.clear();
            if(QDir(mFolder).exists()){
                QFuture<QStringList> future = QtConcurrent::run([=]() {
                    QStringList files;
                    QDirIterator it(mFolder, mNameFilters, QDir::Files, QDirIterator::Subdirectories);
                    while (it.hasNext()){
                        files<<it.next();
                    }
                    return files;
                });
                QStringList fullNames = future.result();
                for(const QString& fullName: fullNames){
                    File file{fullName};
                    m_all_dirs << file;
                }
            }
            endResetModel();
        }
        QString mFolder;
        QList<File> m_all_dirs;
        QStringList mNameFilters;
    };
    
    #endif // FILEMODEL_H
    

    然后在.qml中注册并使用

    <强>的main.cpp

    qmlRegisterType<FileModel>("com.eyllanesc.filemodel", 1,0, "FileModel");
    

    <强> main.qml

    import QtQuick 2.9
    import QtQuick.Controls 2.2
    import QtMultimedia 5.8
    
    import com.eyllanesc.filemodel 1.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Tabs")
    
        SwipeView {
            id: swipeView
            anchors.fill: parent
            currentIndex: tabBar.currentIndex
    
            Page {
    
                ListView {
                    id: lv
                    width: 200; height: 400
    
                    Component {
                        id: fileDelegate
                        Text { text: fileName
                            MouseArea{
                                anchors.fill: parent
                                onClicked: playMusic(index)
                            }
                        }
                    }
    
                    model: FileModel{
                        id: myModel
                        folder: "/home/eyllanesc"
                        nameFilters: ["*.mp4"]
                    }
    
                    delegate: fileDelegate
                }
    
                Button {
                    id: button
                    anchors.top: lv.bottom
                    width: parent.width
                    text: "Play"
                    background: Rectangle {
                        implicitHeight: 40
                        border.color: "#26282a"
                        border.width: 2
                        radius: 4
                    }
                    onClicked: playMusic(0)
                }
            }
    
            Page {
                MediaPlayer {
                    id: player
                    onStopped: {
                        if(status===MediaPlayer.EndOfMedia){
                            playMusic((lv.currentIndex+1) % lv.count)
                        }
                    }
                }
    
                VideoOutput {
                    id: video
                    anchors.fill: parent
                    source: player
                }
            }
        }
    
        function playMusic(index){
            player.stop()
            player.source = myModel.get(index).url
            player.play()
            swipeView.setCurrentIndex(1)
        }
    
        footer: TabBar {
            id: tabBar
            currentIndex: swipeView.currentIndex
    
            TabButton {
                text: qsTr("Page 1")
            }
            TabButton {
                text: qsTr("Page 2")
            }
        }
    }
    
    1. 另一种解决方案是使用QQmlListProperty并公开这些属性:
    2. #ifndef FILEMANAGER_H
      #define FILEMANAGER_H
      
      #include <QDirIterator>
      #include <QFileInfo>
      #include <QFuture>
      #include <QObject>
      #include <QQmlListProperty>
      #include <QUrl>
      #include <QVector>
      #include <QtConcurrent>
      
      class File: public QObject{
          Q_OBJECT
          Q_PROPERTY(QString fileName READ fileName CONSTANT)
          Q_PROPERTY(QUrl url READ url CONSTANT)
      public:
          File(const QString fullPath="", QObject *parent = nullptr):QObject(parent){
              mFullPath = fullPath;
          }
          QString fileName() const
          {
              return QFileInfo(mFullPath).fileName();
          }
          QUrl url() const{
              return QUrl::fromLocalFile(mFullPath);
          }
      
      private:
          QString mFullPath;
      };
      
      class FileManager : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(QQmlListProperty<File> files READ files NOTIFY filesChanged)
          Q_PROPERTY(QString folder READ folder WRITE setFolder NOTIFY folderChanged)
          Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
      public:
          explicit FileManager(QObject *parent = nullptr):QObject(parent){}
          QQmlListProperty<File> files(){
              return QQmlListProperty<File>(this, this,
                                            &FileManager::filesCount,
                                            &FileManager::file);
          }
      
          QString folder() const
          {
              return mFolder;
          }
      
          void setFolder(const QString &folder)
          {
              if(mFolder == folder)
                  return;
              mFolder = folder;
              emit folderChanged();
              findFiles();
          }
      
          int filesCount() const{
              return mFiles.count();
          }
      
          File *file(int index) const{
              return mFiles.at(index);
          }
          QStringList nameFilters() const{
              return mNameFilters;
          }
      
          void setNameFilters(const QStringList &nameFilters){
              if(mNameFilters == nameFilters)
                  return;
              mNameFilters = nameFilters;
              emit nameFiltersChanged();
              findFiles();
          }
      
      signals:
          void folderChanged();
          void filesChanged();
          void nameFiltersChanged();
      private:
      
          void findFiles( ) {
              mFiles.clear();
              if(QDir(mFolder).exists()){
                  QFuture<QStringList> future = QtConcurrent::run([=]() {
                      QStringList files;
                      QDirIterator it(mFolder, mNameFilters, QDir::Files, QDirIterator::Subdirectories);
                      while (it.hasNext()){
                          files<<it.next();
                      }
                      return files;
                  });
      
                  for(const QString& fullName:  future.result()){
                      File* file = new File(fullName);
                      mFiles << file;
                  }
              }
              emit filesChanged();
          }
      
          static int filesCount(QQmlListProperty<File>* list){
              return reinterpret_cast<FileManager* >(list->data)->filesCount();
          }
          static File* file(QQmlListProperty<File>* list, int index){
              return reinterpret_cast<FileManager* >(list->data)->file(index);
          }
          QVector<File *> mFiles;
          QString mFolder;
          QStringList mNameFilters;
      };
      
      #endif // FILEMANAGER_H
      

      然后在.qml中注册并使用

      <强>的main.cpp

      qmlRegisterType<FileManager>("com.eyllanesc.filemanager", 1,0, "FileManager");
      

      <强> main.qml

      import QtQuick 2.9
      import QtQuick.Controls 2.2
      import QtMultimedia 5.8
      
      import com.eyllanesc.filemanager 1.0
      
      ApplicationWindow {
          visible: true
          width: 640
          height: 480
          title: qsTr("Tabs")
      
          FileManager{
              id: manager
              folder: "/home/eyllanesc"
              nameFilters: ["*.mp4"]
          }
      
          SwipeView {
              id: swipeView
              anchors.fill: parent
              currentIndex: tabBar.currentIndex
      
              Page {
      
                  ListView {
                      id: lv
                      width: 200; height: 400
      
                      Component {
                          id: fileDelegate
                          Text { text: fileName
                              MouseArea{
                                  anchors.fill: parent
                                  onClicked: playMusic(index)
                              }
                          }
                      }
      
                      model: manager.files
                      delegate: fileDelegate
                  }
      
                  Button {
                      id: button
                      anchors.top: lv.bottom
                      width: parent.width
                      text: "Play"
                      background: Rectangle {
                          implicitHeight: 40
                          border.color: "#26282a"
                          border.width: 2
                          radius: 4
                      }
                      onClicked: playMusic(0)
                  }
              }
      
              Page {
                  MediaPlayer {
                      id: player
                      onStopped: {
                          if(status===MediaPlayer.EndOfMedia){
                              playMusic((lv.currentIndex+1) % lv.count)
                          }
                      }
                  }
      
                  VideoOutput {
                      id: video
                      anchors.fill: parent
                      source: player
                  }
              }
          }
      
          function playMusic(index){
              player.stop()
              player.source = manager.files[index].url
              player.play()
              swipeView.setCurrentIndex(1)
          }
      
          footer: TabBar {
              id: tabBar
              currentIndex: swipeView.currentIndex
      
              TabButton {
                  text: qsTr("Page 1")
              }
              TabButton {
                  text: qsTr("Page 2")
              }
          }
      }
      

      这两个例子都可以在以下链接中找到