I'm using FolderListModel to get list of files in a specific directory in QML.
FolderListModel {
id: folderModel
nameFilters: ["*.json"]
rootFolder: "file:///" + applicationDirPath + "/Schedules"
folder: "file:///" + applicationDirPath + "/Schedules"
}
This is working fine in windows. However, I'm having problem with Ubuntu. So I changed the code to this:
FolderListModel {
id: folderModel
nameFilters: ["*.json"]
rootFolder: applicationDirPath + "/Schedules"
folder: applicationDirPath + "/Schedules"
}
But this is not working either :( Even I have tried to hard code the path but it didn't help also:
FolderListModel {
id: folderModel
nameFilters: ["*.json"]
folder: "/home/test/Schedules"
rootFolder: "/home/test/Schedules"
}
Any hints will be appreciated
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})/, "");
}
}
Hello guys i have found into this repository
https://github.com/dept2/Poppler-QML-plugin
a qml plugin for show a pdf file into a qml file, but i don't know how i can use it someone can help me?
In ubuntu 18.04 version i have found this plugin with command line sudo apt-cache search poppler and i have installed the package but i have the same problem , how i can use it ?
Thanks in advance
There are 2 possible methods:
1. Compile and install the plugin:
To install this package I must install the plugin for it first download the project, open a terminal in the project directory and execute the following:
qmake
make
sudo make install
Then in the .qml import the module, the Poppler item provides an imageProvider so you should use an Image as I show below:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.11
import org.docviewer.poppler 1.0 // <--- import
import QtQuick.Dialogs 1.3
Window {
id: win
visible: true
width: 640
height: 480
title: qsTr("Poppler Example")
function urlToPath(urlString) {
var s
if (urlString.startsWith("file:///")) {
var k = urlString.charAt(9) === ':' ? 8 : 7
s = urlString.substring(k)
} else {
s = urlString
}
return decodeURIComponent(s);
}
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: shortcuts.home
nameFilters: ["PDF files (*.pdf)", "All files (*)"]
onAccepted: timer.running = true
Component.onCompleted: visible = true
}
Timer {
id: timer
interval: 100; repeat: false
onTriggered: {
poppler.path = urlToPath(""+fileDialog.fileUrl)
view.focus = true
}
}
Poppler{
id: poppler
}
ListView{
id: view
height: parent.height
width: 100
model: poppler.numPages
delegate: Image{
id: image
width: parent.width
source: poppler.loaded? "image://poppler/page/" + (modelData+1): ""
sourceSize.width: width
MouseArea{
anchors.fill: parent
onClicked: {
image.ListView.view.currentIndex = index
image.ListView.view.focus = true
}
}
}
}
Flickable {
height: parent.height
anchors.left: view.right
anchors.right: parent.right
contentWidth: bigImage.width;
contentHeight: bigImage.height
boundsBehavior: Flickable.StopAtBounds
Image{
id: bigImage
sourceSize.width: win.width - view.width
source: (poppler.loaded && view.currentIndex >= 0)? "image://poppler/page/"+(view.currentIndex+1): ""
}
}
}
Output:
2. Create .pri
I have created a .pri that is a simple way to attach the files to the project:
poppler-qml.pri:
INCLUDEPATH += $$PWD
SOURCES += \
$$PWD/pdfModel.cpp \
$$PWD/pageImageProvider.cpp
HEADERS += \
$$PWD/pdfModel.h \
$$PWD/pageImageProvider.h
unix|win32: LIBS += -lpoppler-qt5
The files must have the following structure:
poppler-qml
├── pageImageProvider.cpp
├── pageImageProvider.h
├── pdfModel.cpp
├── pdfModel.h
└── poppler-qml.pri
And then add it to your .pro:
...
include(poppler-qml/poppler-qml.pri)
and main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <pdfModel.h>
int main(int argc, char *argv[])
{
qputenv("POPPLERPLUGIN_DEBUG", "1"); /// enable debug
qmlRegisterType<PdfModel>("org.docviewer.poppler", 1, 0, "Poppler");
...
For example in the following link you can find an example.
Note:
The initial code of the plugin has a bug because if it asks for a page that does not exist the application should return a null QImage but as it does not do the verification the application can be broken
page = document->page(numPage -1);
if(!page)
return result;
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.