Search code examples
c++qtaudioqmlmultimedia

QML Multimedia play all mp3 in a folder


I am trying to build a simple media player in QML . I can't use QFile Dialog as its a single window application running on EGLFS . I managed so far to build a simple file browser for QML and can play a mp3 from a fixed location. But here is where I am stuck:

  1. How do I set the current selected file from the treeview as source for my audio ?

  2. How can I get the Audio play each file with file ending mp3 from the selected folder?

Thanks for your help

.pro file

QT += qml quick multimedia widgets
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += qml.qrc
QML_IMPORT_PATH =
QML_DESIGNER_IMPORT_PATH =
DEFINES += QT_DEPRECATED_WARNING
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtQml>
#include <QFileSystemModel>


int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setOrganizationName("Power-Tune");
app.setOrganizationDomain("power-tune.org");
app.setApplicationName("PowerTune");

QQmlApplicationEngine engine;
//
QFileSystemModel model;
model.setRootPath("/");
engine.rootContext()->setContextProperty("my_model", &model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));


return app.exec();

}

my main.qml :

import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1 
import QtQuick.Controls 1.4
import QtMultimedia 5.8

ApplicationWindow {
    visible: true
    width: 800
    height: 480
    minimumWidth: 800
    minimumHeight: 480
    title: qsTr("PowerTune ")
    // visibility: "FullScreen"
    color: "black"
    Rectangle {
        width: parent.width
        height: parent.height
        property bool playing: false
        Audio {
            id: playMusic
            //source: currently selected file in TreeView 
        }
        Button {
            id: previous
            text: "previous"
            width: 100
            anchors.right: playpause.left
            //  onClicked: select previous item in current folder
        }
        Button {
            id: playpause
            text: "play/pause" //playing ? "Stop music" : "Start music"
            width: 100
            anchors.right: next.left
            onClicked: {
                if(playing == true) {
                    playMusic.stop()
                    playing = false
                } else {
                    playMusic.play()
                    playing = true
                }
            }
        }
        Button {
            id: next
            text: "next"
            width: 100
            anchors.right: parent.right
        }
        TreeView {
            id:mp3selector
            width: parent.width/2
            height: parent.height
            TableViewColumn {
                title: "Name"
                role: "fileName"
                width: 300
            }
            model: my_model
        }
    }
}

Solution

  • Couple of notes:

    property bool playing: false
    

    Properties are better to be defined at top of hierarchy so that they accessible in all children, so prefer to put it directly in ApplicationWindow not in Rectangle element.

    And, I think TreeView is not a suitable choice (Its a Quick Controls 1.0 element not available in Quick Controls 2.0 , and for mixing check this post);

    You can do the model directly from QML, using a ListView with FolderListModel, you only need an additional of decorations for highlighting and selecting of files with mouse .. that's all, TreeView could be replaced with below code, it works and fancy!

    ...
    import QtQuick.Controls 2.2
    import Qt.labs.folderlistmodel 2.1
    ...
    
        ListView {
            id: list
            width: parent.width/2
            height: parent.height
            model: folderModel
            onCurrentIndexChanged: {
                // This will handle changing playlist with all possible selection methods
                playMusic.source = folderModel.get(currentIndex, "fileURL")
            }
            FolderListModel {
                id: folderModel
                folder: "file:///MP3/"
                showDirs: false
                nameFilters: ["*.mp3"]
            }
            delegate: Component {
                Item {
                    width: parent.width
                    height: 40
                    Column {
                        Text { text: fileName }
                    }
                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            list.currentIndex = index
                        }
                    }
                }
            }
            highlight: Rectangle {
                color: 'grey'
            }
            focus: true
        }
    

    For your buttons onClicked just handle currentIndex of the ListView , for example in the next button add:

    onClicked: list.currentIndex += 1
    

    you also need to add some code to avoid getting index out of range or -1 ...etc.