c++qtqmlqtquick2qt-quick

Picking either a file or a folder in QtQuick


I'm using QT6 for working with DICOM (.dcm) file format. It can be presented either as a file or a folder. I want to use a picker, that allows me to pick folder and files.

As I see here, the Qt 5.15 allows that by selectFolder property, but in Qt 6.x is was removed.

As I see here now it requires a C++ hack for it.

Can it be done with a QML tools in Qt6? (Qt 6.4 to be more precise)


Solution

  • In Qt5.x you had FileDialog and, yes, it did have a selectFolder boolean which could only be true or false. Not both. So, you cannot have a single FileDialog that allows you to select either file or folder at the same time.

    In Qt6.x you have FileDialog and FolderDialog. So, again, you cannot have a single dialog that allows you to select either file or folder at the same time.

    Instead, you can consider rolling your own. As a starting point, you can consider using Qt.labs.folderlistmodel so you needn't create any code in C++. The following is a demonstration of how you may go about creating a file/folder dialog that works with both files and folders (it is a demo only, and, by no means complete):

    import QtQuick
    import QtQuick.Controls
    
    Page {
        FileFolderDialog {
            id: fileFolderDialog
            folder: "file:///tmp"
            nameFilters: ["*.*"]
            onAccepted: result.text = fileUrl
            onRejected: result.text = "rejected"
        }
        Button {
            anchors.centerIn: parent
            text: qsTr("Open")
            onClicked: fileFolderDialog.open()
        }
        footer: Text {
            id: result
        }
    }
    
    // FileFolderDialog.qml
    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    import Qt.labs.folderlistmodel
    Dialog {
        id: fileFolderDialog
        x: (parent.width - width) / 2
        y: (parent.height - height) / 2
        implicitWidth: 500
        implicitHeight: 400
        property alias folder: folderModel.folder
        property alias nameFilters: folderModel.nameFilters
        property url fileUrl
        standardButtons: Dialog.Ok | Dialog.Cancel
        ListView {
            id: fileFolderView
            anchors.fill: parent
            clip: true
            currentIndex: -1
            model: FolderListModel {
                id: folderModel
                folder: "file:/tmp"
                nameFilters: ["*.*"]
            }
            delegate: ItemDelegate {
                icon.source: folderModel.isFolder(index) ? "folder.svg" : "file.svg"
                width: ListView.view.width - 20
                text: fileName
                checkable: true
                onClicked: {
                    fileFolderView.currentIndex = index;
                    fileFolderDialog.fileUrl = fileFolderDialog.folder + "/" + fileName
                }
            }
            highlight: Rectangle { color: "lightsteelblue" }
            ScrollBar.vertical: ScrollBar {
                width: 20
                policy: ScrollBar.AlwaysOn
            }
        }
    }
    
    // one.txt
    tst
    
    // two.txt
    tst
    
    // three/three-a.txt
    tst
    
    // three/three-b.txt
    tst
    
    // four.txt
    tst
    
    // folder.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30 7H16l-1-2H5L4 7H2v20h28zm-1 19H3V12h26zm0-15H3V8h1.618l1-2h8.764l1 2H29z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
    
    // file.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M27 9.699L19.3 2H5v28h22zM26 29H6V3h12v8h8zm-7-19V3l7 7z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
    

    You can Try it Online!

    References: