How to limit amount of files to load using QML FileDialog? I could raise a message if count of selected files is bigger than 5 for example. But it seems like bad solution.
FileDialog {
id: fileDialog
title: qsTr("Please select an image")
folder: shortcuts.pictures
selectMultiple: true
selectFolder: false
nameFilters: [ "Images (*.png *.jpg *.jpeg *.gif)" ]
onAccepted: {
for(var i = 0; i < fileDialog.fileUrls.length; i++){ //bigger than 5 what to do?
urlModel.append({
url: fileUrls[i]
})
}
}
onRejected: {}
}
Related
If one wanted to do it from C++, one can do:
QDirIterator it(":", QDirIterator::Subdirectories);
while (it.hasNext()) {
qDebug() << it.next();
}
However, if I wanted to do the same from within QML / Javascript, how would I do that?
I would do it with a FolderListModel. Here I modified the example found here to show everything in the resource table.
ListView {
width: 200; height: 400
FolderListModel {
id: folderModel
folder: "qrc:/"
nameFilters: ["*"]
}
Component {
id: fileDelegate
Text { text: fileName }
}
model: folderModel
delegate: fileDelegate
}
I need to realise list of images, which are chosen by user (folder) and implemet it in a list.
I have some trouble with source in object Image. In this way I see in console "You chose path..", but my images doesn't appear. Why? What's the right path for source?
The path isn't static because the user choose a folder with many pictures in it, so what should I do?
ApplicationWindow {
id:window;
visible: true
FileDialog {
id: fileDialog;
nameFilters: ["Image files (*.jpg *.png *.jpeg)"]
selectFolder: true;
onAccepted{
console.log("You chose " + fileDialog.fileUrl
}
listView.model = fileDialog.fileUrls;
}
......
ListView {
id: listView
visible: true;
orientation: Qt.Vertical
delegate: {
Image{
id: img
width: 40
height:40
source: model(????)
}
}
....
}
I think you misunderstood what fileDialog.fileUrls gives you. It doesn't give you a list of files in the folder that you chose. It gives you a list of the files or folders that you selected. You still need to search the directory for the files that you want. Thankfully, Qt provides a FolderListModel to do that. So here's a cleaned up example that does this:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.15
import QtQuick.Dialogs 1.2
import Qt.labs.folderlistmodel 2.15
Window {
id: window
width: 640
height: 480
visible: true
Button {
id: btn
text: "Open"
onClicked: fileDialog.open();
}
FileDialog {
id: fileDialog;
selectFolder: true;
onAccepted: folderModel.folder = fileDialog.fileUrl;
}
ListView {
id: listView
anchors.top: btn.bottom
width: 200
height: 400
model: FolderListModel {
id: folderModel
nameFilters: ["*.jpg", "*.png", "*.jpeg"]
showDirs: false
}
delegate: Image {
id: img
width: 40
height: 40
source: fileUrl
}
}
}
First you need add the url paths to the model and then use it. Take care about the file prefix. Something like this :
FileDialog {
id: fileDialog;
selectFolder: true;
onAccepted: updateFiles(fileDialog.files)
}
ListView {
id: listView
anchors.top: btn.bottom
width: 200
height: 400
model: FolderListModel {
id: folderModel
}
delegate: Image {
id: img
width: 40
height: 40
source: listView.model.get(index).fileUrl
}
}
function updateFiles(fileList){
console.log(fileList)
console.log("You chose file(s): " + fileList.fileUrls)
console.log("Num files: " + fileList.length)
for(var i = 0; i < fileList.length; i++){
var path = fileList[i];
path = stripFilePrefix(path);
var newFileUrl = {
"fileUrl": path
};
folderModel.append(newFileUrl);
}
}
function stripFilePrefix(filePath) {
if (Qt.platform.os === "windows") {
return filePath.replace(/^(file:\/{3})|(file:)|(qrc:\/{3})|(http:\/{3})/, "")
}
else {
return filePath.replace(/^(file:\/{2})|(qrc:\/{2})|(http:\/{2})/, "");
}
}
I have some problem with the loop. I'm trying to load img from browserfile and show others in 3s as image - slide. I used while loop
FileDialog {
id: fileDialog
visible: false
title: "Choose a file"
property url defaultz: "E:\IMG"
folder: defaultz
selectMultiple: true
nameFilters: [ "Image files (*.jpg *.png *.bmp)", "All files (*)" ]
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)
console.log(fileDialog.fileUrls.length)
click.visible = false
//title.visible = false
while(i<fileDialog.fileUrls.length){
loop()
}
}
onRejected: {
console.log("Canceled")
fileDialog.visible = false
click.visible = false
}
Component.onCompleted: visible = false
}
Image {
id: show
visible: false
x:0
y:0
width: 300
height: 300
Timer{
id: tmr
interval: 5000
running: false
repeat: false
onTriggered: {
show.visible = false
}
}
}
function loop(){
show.source = fileDialog.fileUrls[i]
show.visible = true
tmr.running = true
i++
}
When loop() is called, it will run show.source = fileDialog.fileUrls[i] to stopped. After that, show.visible = true and tmr.running will be called.
Someone help me please?
Problem is with while, i value reached to the end before the time triggers.
One solution will be calling the loop on expiry of timer i.e onTriggered and stop the timer after showing all the selected pictures in loop function.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property int i:0
FileDialog {
id: fileDialog
visible: false
title: "Choose a file"
property url defaultz: "E:\IMG"
folder: defaultz
selectMultiple: true
nameFilters: [ "Image files (*.jpg *.png *.bmp)", "All files (*)" ]
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)
console.log(fileDialog.fileUrls.length)
//click.visible = false
//title.visible = false
// while(i<fileDialog.fileUrls.length){
// loop()
// }
loop(); // show first picture immediately
tmr.start(); // start timer after selection
}
onRejected: {
console.log("Canceled")
fileDialog.visible = false
//click.visible = false
}
Component.onCompleted: {fileDialog.visible = true
}
}
Image {
id: show
visible: false
x:0
y:0
width: 300
height: 300
Timer{
id: tmr
interval: 5000
running: false
repeat: true
onTriggered: {
show.visible = false
show.visible = false
i++
loop()
console.log("triggered: " + i)
}
}
}
function loop(){
if(i<fileDialog.fileUrls.length)
{
show.source = fileDialog.fileUrls[i]
console.log("showing: " + i + " " + fileDialog.fileUrls[i])
show.visible = true
}else
{
tmr.stop(); // stop the timer
console.log("stopped")
}
}
}
Intention of the following code is to let the user select a folder of photos, and then display those photos one by one.
PhotoViewer.qml
import QtQuick 2.0
import QtQuick.Dialogs 1.0 // FileDialog
import Qt.labs.folderlistmodel 2.1 // FolderListModel
Item
{
id: head
property url path
property int i: 0
height: 500; width: 500
FileDialog
{
id: photoDirectoryFileDialog
title: "Select the photo directory:"
selectFolder: true
visible: true
height: parent.height; width: parent.width
onAccepted: head.path = fileUrl
}
ListView
{
FolderListModel
{
id: folderModel
folder: photoDirectoryFileDialog.fileUrl
nameFilters: ["*.jpg"]
}
Component
{
id: fileDelegate
Text { text: fileName }
}
model: folderModel
delegate: fileDelegate
}
// Show photos
Image
{
id: image
source: ""
}
MouseArea
{
anchors.fill: parent
onClicked:
{
console.log ("fsdfsdf: " + i + " --- " + photoDirectoryFileDialog.fileUrl + "/" + folderModel.get (i, folderModel.fileName))
image.source = photoDirectoryFileDialog.fileUrl + "/" + folderModel.get (i, folderModel.folder.fileName)
i++
}
}
}
main.qml
import QtQuick 2.4
import QtQuick.Window 2.2
Window
{
id: rootWindow
visible: true
height: 700; width: height
PhotoViewer
{
height: rootWindow.height; width: rootWindow.width
}
}
Output:
QML debugging is enabled. Only use this in a safe environment.
qml: fsdfsdf: 0 --- file:///home/***/Pictures/Wallpapers/undefined
qrc:/PhotoViewer.qml:43:5: QML Image: Cannot open: file:///home/***/Pictures/Wallpapers/undefined
qml: fsdfsdf: 1 --- file:///home/***/Pictures/Wallpapers/undefined
qml: fsdfsdf: 2 --- file:///home/***/Pictures/Wallpapers/undefined
As you can see in the output, I am receiving "undefined" as file name in the output. How to fetch files one by one from FolderListModel in QML?
Fixed this up for you. 2 things, the FileDialog must be shown after setting the selectFolder property, so we do it on the onCompleted slot (This is from the FileDialog docs)
And fixed accessing the model item properties, using the more convenient fileURL property.
Also add a check so the i counter rolls over when hitting the end of the list.
import QtQuick 2.0
import QtQuick.Dialogs 1.0 // FileDialog
import Qt.labs.folderlistmodel 2.1 // FolderListModel
Item
{
id: head
property int i: 0
height: 500; width: 500
FileDialog
{
id: photoDirectoryFileDialog
title: "Select the photo directory:"
selectFolder: true
height: parent.height; width: parent.width
onAccepted: {
console.log("selected folder: " + folder)
}
Component.onCompleted: visible = true
}
ListView
{
FolderListModel
{
id: folderModel
folder: photoDirectoryFileDialog.folder
nameFilters: ["*.jpg"]
}
Component
{
id: fileDelegate
Text { text: fileName }
}
model: folderModel
delegate: fileDelegate
}
// Show photos
Image
{
id: image
source: ""
}
MouseArea
{
anchors.fill: parent
onClicked:
{
console.log ("fsdfsdf: " + i + " --- " + folderModel.get (i, "fileURL"))
image.source = folderModel.get (i, "fileURL")
if (++i == folderModel.count) i = 0
}
}
}
I am the OP of this thread, and I found that the problem was that I had forgotten that the second variable of the function get is a string.
That means that the property fileName has to be passed in "", as shown below.
In the following culprit code,
console.log ("fsdfsdf: " + i + " --- " + photoDirectoryFileDialog.fileUrl + "/" + folderModel.get (i, folderModel.fileName))
image.source = photoDirectoryFileDialog.fileUrl + "/" + folderModel.get (i, folderModel.folder.fileName)
folderModel.fileName and folderModel.folder.fileName have to replaced by "fileName":
console.log ("fsdfsdf: " + i + " --- " + photoDirectoryFileDialog.fileUrl + "/" + folderModel.get (i, "fileName"))
image.source = photoDirectoryFileDialog.fileUrl + "/" + folderModel.get (i, "fileName")
I have made a qml file named fileDialog.qml and which use element FileDialog{} available from qt5
http://qt-project.org/doc/qt-5.1/qtquickdialogs/qml-qtquick-dialogs1-filedialog.html.
Whenever i need the location of resource i want to use fileDialog.qml as component and set all the properties like title, filter etc. These are working fine but when i tried to use id.fileUrl then no response. details are given below.
The file fileDialog.qml is
import QtQuick 2.1
import QtQuick.Dialogs 1.0
FileDialog {
id: fileDialog
objectName: "fileBrowser"
title: "Add New Layer"
visible: false
property alias selectedFilename: fileDialog.fileUrls
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)//-------- (1)
}
onRejected: {
console.log("Canceled")
}
//Component.onCompleted: visible = true
}
Now using this as component when Browse(an item in QML to be used like button) button is clicked then i am performing following steps.
onClicked: {
//Default Values fileDialog.{selectExisting = true, selectFolder = false}
fileDialog.title = "Add New Image"
//fileDialog1.selectMultiple = true
fileDialog.nameFilters = ["Image File (*.png *.jpg *.bmp)"]
//fileDialog.fileUrls
//string path
fileDialog.visible = true
console.log(" Image chosen: " + fileDialog.fileUrl + " in image")//--- (2)
}
The line (1) is working fine but but (2) is not working. The output of (2) line in console is just Image chosen: in image.
I don't understand what am I doing wrong here, because when I am setting other(like title, filer) property of component fileDialog its working but not for the fileUrl or fileUrls.
Please somebody suggest how to get the fileUrl when using it as component.
Thanks,
I think what you're trying to do is creating a special FileDialog component that fits your needs.
First, let's call this component "MyFileFialog" saved in MyFileDialog.qml.
// MyFileDialog.qml
import QtQuick 2.0
import QtQuick.Dialogs 1.0
Item {
id: root
property alias title: qmlFileDialog.title
property alias fileUrl: qmlFileDialog.fileUrl
property alias fileUrls: qmlFileDialog.fileUrls
signal accepted()
signal rejected()
function open() { qmlFileDialog.open() }
function close() { qmlFileDialog.close() }
FileDialog {
id: qmlFileDialog
modality: Qt.WindowModal
nameFilters: ["Image File (*.png *.jpg *.bmp)"]
onAccepted: root.accepted()
onRejected: root.rejected()
}
}
There are now a bunch of connections between MyFileDialog and FileFialog:
modality and nameFilters are fixed
title, fileUrl, fileUrls are passed between both components
when the FileDialog is accepted or rejected, the MyFileDialog will be as well
when you open() or close() your MyFileDialog, the inner FleDialog will open or close
Now that you have your very own MyFileDialog, you can use it:
Button {
text: "open"
MyFileDialog {
id: saveFileDialog
title: qsTr("Save to ...")
onRejected: {
console.log("Canceled")
}
onAccepted: {
console.log("File selected: " + fileUrl)
}
}
onClicked: {
saveFileDialog.open()
}
}
Just a try. From documentation, you can see that fileUrl property is only set if you make a single file selection. So you are right to expect it to be setted by your FileDialog
The problem is that you try to display fileUrl before the FileDialog is closed I think.
Showing a modal dialog probably don't block your function execution.
As you do in your base component fileDialog.qml, you can put a handler on onAccepted. When your handler will be called, fileUrl property will be available.
edit:
Browse {
id: browser
signal fileChosen
FileDialog {
id: fileDialog
//configure your fileDialog here
//...
//emit parent signal when done
onAccepted: browser.fileChosen();
}
onClicked: {
fileDialog.open();
}
onFileChosen: {
//fileUrl should be available here
console.log(fileDialog.fileUrl);
}
}
I got a solution after reading the answer of #jbh whose answer helps in accessing fileUrl outside FileDialog{} element in same qml file but that's not an answer to my question.
Element FileDialog{} have an signal accepted so we use this signal to connect to a method and then access the fileUrl or Urls. This how fileBrowser.qml look like.
import QtQuick 2.1
import QtQuick.Dialogs 1.0
FileDialog {
id: fileDialog
objectName: "fileBrowser"
title: "Add New Layer"
visible: false
//property alias selectedFilename: fileDialog.fileUrls
// signal fileChosen
// onAccepted: {
// console.log("You chose: " + fileDialog.fileUrls)
// fileChosen();
// }
onRejected: {
console.log("Canceled")
}
//Component.onCompleted: visible = true
}
onAccepted slot above is commented and we use accepted signal to access fileUrl.
This is how a qml file will look when using fileBrowser.qml as component whenever file dialog is required.
Item{
id: popup
Rectangle{
id: browse button
// properties setting for construction a button such as width, color, mouse area, states, etc..
// the method where we can use the URLS
function dialogAccepted(){
fileDialog.accepted.disconnect(dialogAccepted)
filePath.text = Qt.resolvedUrl( fileDialog.fileUrl ).toString()// to set the text in text field
console.log("You Chose in elev: " + fileDialog.fileUrl)
//browseButtonClicked(checkBox.checked)
}
onClicked: {
//Default Values fileDialog.{selectExisting = true, selectFolder = false}
fileDialog.title = "Add New Image"
//fileDialog1.selectMultiple = true
fileDialog.nameFilters = ["Image File (*.png *.jpg *.bmp)"]
fileDialog.visible = true
fileDialog.accepted.connect(dialogAccepted)
}
}
}
well, this worked for me but i am still facing problem with how to resolve Url when multiple file is selected and how to send it to c++ file so that it is accepted.