Qt QML中的音频播放列表

Qt QML中的音频播放列表,qt,audio,qml,qtquick2,playlist,Qt,Audio,Qml,Qtquick2,Playlist,我正在qml上制作一个简单的播放列表播放器。我的意思是有一个音频播放器,它在文件夹中播放扩展名为.mp3的文件。但是这个“播放列表播放器”假设整个文件夹都是一个播放列表。因此,我将playlist文件夹的路径作为程序的命令行参数,例如/playlist\u player/home/user/playlist folder,程序在playlist文件夹中播放整个mp3。但由于qml不理解星号(*)之类的wildchar,因此我使用QDir查找MP3的名称,找到MP3的名称,并使用本文介绍的方法将这

我正在qml上制作一个简单的播放列表播放器。我的意思是有一个
音频
播放器,它在文件夹中播放扩展名为
.mp3
的文件。但是这个“播放列表播放器”假设整个文件夹都是一个播放列表。因此,我将playlist文件夹的路径作为程序的命令行参数,例如
/playlist\u player/home/user/playlist folder
,程序在playlist文件夹中播放整个mp3。但由于qml不理解星号(*)之类的wildchar,因此我使用
QDir
查找MP3的名称,找到MP3的名称,并使用本文介绍的方法将这些字符串暴露给qml。所以我有一个QObject派生的类名
FileNames
,它有
Q_属性(QStringList mp3List READ mp3List)
。因此,在
文件名的构造函数上,我查找命令行中给定的路径,检测扩展名为.mp3s的文件,并将这些路径推回
文件名::mp3List
。在
main.cpp
上,我在实例化
QQuickView
对象之后实例化了一个
FileNames
对象,并使用
qqqmlcontext::setContextProperty
成员函数将
FileNames
对象传递给Qml端

在这之前,一切都正常,我还需要列表中MP3的数量,以便使用
next
函数进行迭代,该函数为qml侧的列表增加
index
值。我知道我可以公开另一个属性来传递
mp3List
的计数,但我最终发现这个解决方案可能不是最好的本机解决方案

这是我写的代码

/* filenames.h */

class FileNames : public QObject {
    Q_OBJECT
    Q_PROPERTY(QStringList mp3List READ mp3List)
    Q_PROPERTY(int mp3ListCount READ mp3ListCount)
public:
    explicit FileNames(QObject *parent = 0);

    QStringList mp3List() const;
    int mp3ListCount() const;
private:
    QStringList m_mp3List;
    int m_mp3ListCount;
};

/* filenames.cpp */

FileNames::FileNames(QObject *parent) :
    QObject(parent), m_mp3ListCount(0)
{
    QString path("/home/user/music/");
    QDir dirname(path);
    QStringList dir = dirname.entryList();

    for (const auto &file : dir)
        if (file.endsWith(".mp3")) {
            m_mp3List.push_back("file://" + path + file);
            ++m_mp3ListCount;
        }
}

QStringList FileNames::mp3List() const
{
    return m_mp3List;
}

int FileNames::mp3ListCount() const
{
    return m_mp3ListCount;
}

/* main.cpp */

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

    FileNames names;

    QQuickView view;

    view.engine()->rootContext()->setContextProperty("names", &names);

    view.setSource(QUrl(QStringLiteral("qrc:///main.qml")));

    view.setResizeMode(QQuickView::SizeRootObjectToView);

    view.showFullScreen();

    return app.exec();
}

/* Playlist.qml */

Item {
    id: root

    property int index: 0
    property MediaPlayer mediaPlayer
    property variant list;
    property int listCount;

    function setIndex(i)
    {
        console.log("setting index to: " + i);
        index = i;
        if (index < 0 || index >= listCount) {
            index = 0;
            mediaPlayer.source = "";
        }
        mediaPlayer.source = list[index];
    }

    function next()
    {
        setIndex(index + 1);
    }

    function previous()
    {
        setIndex(index + 1);
    }

    Connections {
        target: root.mediaPlayer

        onStopped: {
            if (root.mediaPlayer.status == MediaPlayer.EndOfMedia)
            {
                root.next();
                root.mediaPlayer.play();
            }
        }
    }
}

/* main.qml */

Rectangle {
    id: root

    width: 1024
    height: 600

    color: "black"

    Playlist {

        id: playlist

        mediaPlayer: player

        list: names.mp3List
        listCount: names.mp3ListCount
    }

    MediaPlayer {
        id: player
    }

    VideoOutput {
        anchors.fill: parent

        source: player
    }
}
谢谢,,
新浪。

QML类型将满足您的需要。它支持名称过滤等。

< P>使用QML中的C++类型或定义上下文属性在与C++代码集成时是非常好的。C++自然地扩展了QML的可能性,它只是理解C++后端类或C++中新的QML类型的一个问题。有关此主题的进一步讨论,请参阅

根据上面链接的答案和播放列表组件的生存期,使用QML类型而不是上下文属性将是正确的选择。但是,如前所述,QML已经为您提供了正确的组件:。在您的情况下,可以很容易地定义如下:

FolderListModel {
    id: folderModel
    nameFilters: ["*.mp3"]
    showDirs: false
    folder: "file:" + /* CPP PROVIDED PATH */
}
FolderListModel {
    id: fm
    folder: "..."
    showDirs: false
    showDotAndDotDot: false
    nameFilters: ["*.mp3"]
    property bool ready: count > 0
}
您可以使用函数根据属性查询列表中的下一个mp3

一个很大的优点是
FolderListModel
确实会侦听文件夹中的文件更改,这样您就不需要检查文件的添加/删除。最后,但并非最不重要的是,
FolderListModel
可以很容易地集成到GUI实现中,将其用作
ListView
的模型。请看一个例子

补遗 正如OP所指出的,
FolderListModel
是异步工作的。这是一种常见的行为,因为在组件初始化期间执行所有检查可能会导致长时间启动(尤其是对于满是文件的目录)。当
FolderListModel
完成对文件系统的跟踪时,没有可跟踪的属性,因为文件系统检查是连续的,所以有一个属性可能也没有意义。添加
bool
属性可能会有所帮助,如下所示:

FolderListModel {
    id: folderModel
    nameFilters: ["*.mp3"]
    showDirs: false
    folder: "file:" + /* CPP PROVIDED PATH */
}
FolderListModel {
    id: fm
    folder: "..."
    showDirs: false
    showDotAndDotDot: false
    nameFilters: ["*.mp3"]
    property bool ready: count > 0
}
ready
为真时(因为已添加MP3或初始扫描已完成),可能会触发播放器。显然,可以添加其他属性来改进模型的行为