How to dynamically generate files in the build directory?
-
Good morning everyone!
I have a folder of images, and I'm looking to load one in QML based on the corresponding file name in a JSON file.Let's say I would like to load a file named 1.png. In the JSON file, I would need to add the file name
{"imageFile": "1.png"}
and from my handler.cpp I would need to parse the file:
QJsonDocument Document = QJsonDocument::fromJson(Bytes, &SyntaxError); if (SyntaxError.error != QJsonParseError::NoError){ qDebug() << SyntaxError.errorString() << "JSON PARSE ERROR"; } if (Document.isObject()){ m_imageFilePath = QUrl::fromLocalFile(imFolderDir.path()).toString()+ "/" + Document.object().value("imageFile").toString();
This returns the full file path:
"file:///C:/Users/xxx/Documents/xxx/build/Desktop_Qt_6_8_3_llvm_mingw_64_bit-Debug/xxx/images/1.png"
m_imageFilePath is a variable exposed to QML, so I should be able to load it
Image { source: handler.imageFilePath anchors.centerIn: parent.Center width: parent.width height: parent.height }
But I receive a "Cannot open" error. I believe this is because the image file doesn't get generated in the build location of the project (when I check
/build/Desktop_Qt_6_8_3_llvm_mingw_64_bit-Debug/xxxx/Images/1.png in file explorer, the file doesn't exist.) To have Qt generate the file, I can specify the location of the file in CMakeRESOURCES Images/1.png
Here's the problem:
I would need to manually do this for every file in the folder, and if I expand the folder with more images, I would need a more-dynamic way of generating loading them. Is there a way to get the images in my debug directory to be generated in the build directory, without manually inputting the file paths in CMake?Thanks!
-
hmmm you're doing it the wrong way.
If you need the user to be able to add files into a specific path, then the source and build folders are not the place to put those images in the first place.
what you should do is allow the user to specify a directory to put those files into and you save / restore that path with QML Settings or QSettings. You still can do it with a JSON file if you really want to, but QSettings is far more appropriate for that purpose, at least in my opinion.
If you need to monitor the content of the folder and emit a signal when a change has occured in the folder, then you need QFileSystemWatcher. -
Put your images in a resource file so you don't have problems with relative paths anymore: https://doc.qt.io/qt-6/resources.html
-
Put your images in a resource file so you don't have problems with relative paths anymore: https://doc.qt.io/qt-6/resources.html
@Christian-Ehrlicher Hello,
My issue is less so the fact that I have to deal with relative paths. It's the fact that I have to explicitly add paths in the first place. Suppose a user adds multiple images to the empty images folder while the app is running. Because we don't know how many images exist in the folder at runtime, if we were to obtain a path to one of those images, we would need to dynamically assemble a path. This is where the JSON file comes in; it has access to the file name and the extension. But to keep things simple:Essentially, I would like to set a path to the folder, and the app picks up on all the images in the folder. For some reason, Qt doesn't add the contents of the folder to the build folder, so when I run the project, the files don't exist. I need to, at all costs, avoid manually setting image paths, as the number of images in the folder isn't static; it's user-defined.
-
So far:
I understand how to locate folders, including the images folder, but I don't know how to get the images folder with the unknown number of images inside the build folder without specifying them either in CMake or qrc.To my knowledge, this should be possible. I've seen functions like this in major applications, such as Adobe Photoshop, where you can add a folder full of brush files or fonts, and the app will read and add each one to your toolkit
-
Hi,
Usually you have this information in the application settings or in a known hard coded path.
So in the case of your application, you should add that option in a similar fashion. -
if you need it at build time, then the best solution is Qt Resource as @Christian-Ehrlicher already stated, thus you solve the problem of relative path. If the sole reason of that JSON file is about path in source/build directory, that file is not needed. If you didn't state those files to be part of the project, then it's normal they are not copied into the build directory.
Otherwise you can make a python or js script to build that file and call it whenever you need (use a cmake statement to call that script if really needed)if you really needed it for whatever other reason, what I would do is instead of a JSON file is use a JS file instead in which you assign the object to a variable and import that JS file into QML, which spares you from JSON parsing in C++.
In your project you treat that JS file as a QML file./// myfile.js var object = { ... } /// MyComponent.qml import myfile.js as myfile // and use the object as myfile.object
-
if you need it at build time, then the best solution is Qt Resource as @Christian-Ehrlicher already stated, thus you solve the problem of relative path. If the sole reason of that JSON file is about path in source/build directory, that file is not needed. If you didn't state those files to be part of the project, then it's normal they are not copied into the build directory.
Otherwise you can make a python or js script to build that file and call it whenever you need (use a cmake statement to call that script if really needed)if you really needed it for whatever other reason, what I would do is instead of a JSON file is use a JS file instead in which you assign the object to a variable and import that JS file into QML, which spares you from JSON parsing in C++.
In your project you treat that JS file as a QML file./// myfile.js var object = { ... } /// MyComponent.qml import myfile.js as myfile // and use the object as myfile.object
@ankou29666 said in How to dynamically generate files in the build directory?:
If you didn't state those files to be part of the project, then it's normal they are not copied into the build directory.
Yes, this is the case with my situation. I have an image folder that the user can add images to while the app is running, so the files won't necessarily exist at compile time.
@ankou29666 said in How to dynamically generate files in the build directory?:
if you really needed it for whatever other reason, what I would do is instead of a JSON file is use a JS file instead in which you assign the object to a variable and import that JS file into QML, which spares you from JSON parsing in C++.
In your project you treat that JS file as a QML file.I think I may have confused you with the whole point of the JSON file. I tried to avoid going in depth for simplicity's sake, but essentially, the JSON file holds dynamic configuration data for the app, including the image it's associated with and the relative path to said image. I'd say it's required for that reason alone. It needs to be parsed by a C++ class specifically, so the class can signal other classes, as well as get referenced later. Otherwise, I totally agree with your workflow!
-
Hi,
Usually you have this information in the application settings or in a known hard coded path.
So in the case of your application, you should add that option in a similar fashion.@SGaist I'm not sure that I understand. In a practical sense, among many other possibilities, a user could add a file named image1.png or image2.png to the images folder at runtime. How would my app know the full path of the file if there are over 1000 possible image choices? I'd have to hard-code each to get generated at compile time. Because there are many possibilities, I took a more dynamic approach and instead coded the app to read what's in the folder and create paths based on each file. That way, I can select and load a specific file.
The only issue I have is that the files I want to read in the images folder aren't copied over in the "build" version of the project due to the paths not being hard-coded in CMake, That said, the image files don't exist on the working build, and I can't load them. I was hoping that there would be a way to have them generated in the build directory, just like the hard-coded cpp, .h, and QML files...
-
hmmm you're doing it the wrong way.
If you need the user to be able to add files into a specific path, then the source and build folders are not the place to put those images in the first place.
what you should do is allow the user to specify a directory to put those files into and you save / restore that path with QML Settings or QSettings. You still can do it with a JSON file if you really want to, but QSettings is far more appropriate for that purpose, at least in my opinion.
If you need to monitor the content of the folder and emit a signal when a change has occured in the folder, then you need QFileSystemWatcher. -
-
Ahhh, I see... now that I've taken a break, I didn't realize that my entire process was flawed. The user is going to be adding files to the folder at any point in time, so of course it wouldn't be best to generate those files at compile time, lol. Like you've mentioned, I'll just monitor the folder within C++ and have QML react to the changes. Thank you for the help!