如何使用 C++ 模型填充播放列表 qml 类型?

How do I populate a playlist qml type using a c++ model?

我正在构建一个音乐播放器,需要使用此 C++ 模型自动填充播放列表:

static QStringList pathList;   
int main(int argc, char *argv[]){
// ...
// ...
QDirIterator it("E:/", QStringList() << "*.mp3", QDir::Files, QDirIterator::Subdirectories);
        while (it.hasNext()){
            pathList.append(it.next());
        }
    QQmlContext *ctxt1 = engine.rootContext();
    ctxt1->setContextProperty("pathModel", QVariant::fromValue(pathList)); //used model pathmodel
// ...
// ...
}

我在 qml 端的播放列表代码:

Rectangle{
    width: page.width
    height: page.height
    Audio {
           id: player;
           playlist: Playlist {
               id: playlist
               PlaylistItem { source: "song1.ogg"; } //I want this process to be automated instead of doing it manually
           }
       }
       ListView {
           model: playlist;
           delegate: Text {
               font.pixelSize: 16;
               text: source;
           }
       }
       MouseArea {
           anchors.fill: parent;
           onPressed: {
               if (player.playbackState != Audio.PlayingState) {
                   player.play();
               } else {
                   player.pause();
               }
           }
       }
}

我尝试使用应用程序列表视图类型,但我只能 play/pause 单击一首歌曲,无法实现诸如在歌曲结束时自动播放下一首或在选择另一首歌曲时停止当前歌曲等功能。 qt 文档不清楚需要做什么,也没有可用的教程或演示

根据您要实施的内容,有多种解决方案:

  • 如果您打算只在开头加载列表,那么您应该只使用 QList <QUrl>:
// ...
QList<QUrl> sources;
QString folder = "E:/"
QDirIterator it(folder, QStringList() << "*.mp3", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()){
    sources << QUrl::fromLocalFile(it.next());
}
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("sources", QVariant::fromValue(sources));
// ...
// ...
Audio {
    id: player;
    playlist: Playlist {
        id: playlist
        Component.onCompleted: playlist.addItems(sources)
    }
}
// ...
  • 如果你想在程序执行期间添加和删除项目,那么你可以使用模型:
class SourceModel: public QStandardItemModel{
    Q_OBJECT
public:
    enum SourceRoles{
        SourceRole = Qt::UserRole + 1000
    };
    SourceModel(QObject *parent=nullptr):
        QStandardItemModel(parent)
    {
        QHash<int, QByteArray> roles;
        roles[SourceRole] = "source";
        setItemRoleNames(roles);
        connect(this, &QAbstractItemModel::rowsInserted, this, &SourceModel::onRowsInserted);
        connect(this, &QAbstractItemModel::rowsRemoved, this, &SourceModel::onRowsRemoved);
        connect(this, &QAbstractItemModel::modelReset, this, &SourceModel::reset);
    }
    void addSource(const QUrl & url){
        QStandardItem *item = new QStandardItem();
        item->setData(url, SourceRole);
        appendRow(item);
    }
Q_SIGNALS:
    void sourcesInserted(int first, QList<QUrl> sources);
    void sourcesRemoved(int first, int last);
    void reset();
private:
    void onRowsInserted(const QModelIndex &parent, int first, int last){
        QList<QUrl> sources;
        for (int i=first; i <= last; ++i) {
            QModelIndex ix = this->index(i, 0, parent);
            QVariant v = data(ix, SourceRole);
            sources << v.toUrl();
        }
        Q_EMIT sourcesInserted(first, sources);
    }
    void onRowsRemoved(const QModelIndex & /*parent*/, int first, int last){
        Q_EMIT sourcesRemoved(first, last);
    }
};

// ...
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("source_model", &source_model);
// ...
QString folder = "E:/"
QDirIterator it(folder, QStringList() << "*.mp3", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()){
    source_model.addSource(QUrl::fromLocalFile(it.next()));
}
// ...
// ...
Connections{
    target: source_model
    onSourcesInserted: playlist.insertItems(first, sources)
    onSourcesRemoved: playlist.removeItems(first, last);
    onReset: playlist.clear()
}
Audio {
    id: player;
    playlist: Playlist {
        id: playlist
    }
}
// ...
  • 另一种选择是使用 Q_PROPERTY:
class SourceManager: public QObject{
    Q_OBJECT
    Q_PROPERTY(QList<QUrl> sources READ sources  WRITE setSources  NOTIFY sourcesChanged)
public:
    using QObject::QObject;
    QList<QUrl> sources() const{
        return m_sources;
    }
    void setSources(QList<QUrl> sources){
        if (m_sources == sources)
            return;
        m_sources = sources;
        emit sourcesChanged();
    }
Q_SIGNALS:
    void sourcesChanged();
private:
    QList<QUrl> m_sources;
};
// ...
SourceManager source_manager;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("source_manager", &source_manager);
// ...
QList<QUrl> sources;
QString folder = "E:/"
QDirIterator it(folder, QStringList() << "*.mp3", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()){
    sources << QUrl::fromLocalFile(it.next());
}
source_manager.setSources(sources);
// ...
// ...
Connections{
    target: source_manager
    onSourcesChanged: {
        playlist.clear();
        playlist.addItems(source_manager.sources)
    }
}
Audio {
    id: player;
    playlist: Playlist {
        id: playlist
    }
}
// ...