I am trying to reach the qt resource folder without success. It works if I export into an other folder like C:\\Temp\\18_25_21_18_09_2014.svg, but it doesn't work if I use an URL like :/Temp/18_25_21_18_09_2014.svg.
Here is the code:
QString fileName(":/Temp/Temp" + QDateTime(QDateTime::currentDateTime()).toString("hh_mm_ss_dd_MM_yyyy") + ".svg");
QSvgGenerator generator;
generator.setFileName(fileName);
generator.setSize(this->size());
generator.setViewBox(QRect(QPoint(0,0), this->size()));
generator.setTitle(tr("bubble_svg"));
generator.setDescription(tr("bubble_svg"));
_painter.begin(&generator);
_painter.setRenderHint(QPainter::Antialiasing);
_painter.setRenderHint(QPainter::HighQualityAntialiasing);
this->render(&_painter);
_painter.end();
Also I created a prefix called Temp and a folder called Temp.
It looks like that also QDirIterator can reach the folder, only the QSvgGenerator couldn't.
QDirIterator it(":/Temp/Temp", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
qDebug() << "FILE FOUND " << it.next();
}
The result of this part of code:
FILE FOUND ":/Temp/Temp/18_35_19_18_09_2014.svg"
I appreciate every idea. Thanks for dropping by and taking time with the questions!
Ok, I understood and post it as answer.
Unfortunately it is impossible. Qt Resource System forbid this. As documentation said:
The Qt resource system is a platform-independent mechanism for storing binary files in the application's executable. It means that resources are read only, thuis files compiled into the executable, you can't write it because this files storing in your exe file. Especially an executable can’t modify itself while it is running. You’ll have to re-compile the QRC file (using RCC) and then re-build the EXE file, if one of the resources has changed.
As you can see, you should provide another way to storing and using your files.
I hope it was useful for you.
Related
My qt project has .qrc file so my resources files are stored like ":/audio/melody/...".
I need to choose which files to use or not in runtime, so my program stores the resources path in .txt file.
In runtime, my program get these path to string, as variables.
So now I need to use these variables to put [setSource(variables)] methods of any other Qt objects. But it can't.
I tried to convert std::string (which has the file path) to QString, and put it in QtObj.setSource() as QUrl(QString).
But I found the QUrl(QString) has no data(I expected that there was resource path like ":/audio/melody/.. blahblah" in QUrl(QString)).
How can I convert the std::string(which has resource path) to QUrl, in order to use it as a resource path?
Actually, I wonder there is possibility to use resource path as variables.
To get a list of all resources, the files itself and a URL to the file at runtime you can do this:
QHash<QUrl, QFile> list;
QDirIterator it(":", QDirIterator::Subdirectories);
while (it.hasNext()) {
QFile file(it.next());
QUrl url = QUrl::fromLocalFile(file.fileName())
list.insert(url, file);
}
I am currently attempting to create a new directory and create a new file inside of this directory. However, QDir recognizes that this file exists, however when I try to cd to my new directory, the currentPath returns the same value before and after the QDir().cd(dirName)
QDir().cdUp();
if(!QDir(dirName).exists())
QDir().mkdir(dirName);
qDebug() << QDir().currentPath(); // returns a path up from exe dir
if(QDir().cd(dirName))
qDebug() << QDir().currentPath(); //returns the same path as above
Really not sure why this isn't working, I am pretty new to programming and was wondering why this was.
QDir().cd(dirName)
Every time you perform QDir() you're creating a new instance of the object, then you perform an operation on it (i.e., .cd(dirName)), and finally that object goes out of scope and is destroyed; thereby losing all your changes.
Instead you should be creating a single instance and performing all operations on it.
QDir dir;
dir.cd(dirName);
dir.path();
The constructor QDir() creates a QDir object pointing to the program's working directory. QDir()::cd() changes that QDir object directory, however it does not change program directory. If you really want to change current application working directory, see QDir()::setCurrent(const QString & path)
That current application directory is used as relative path for files. So, to create a file in a new directory, you can specify the full file path or to use relative path as:
QDir::setCurrent(new_base_path);
QFile("some_relative_file_name");
...
As I understand it, the way to packages non-code resources such as data files in a Qt app is using the resource system. However, what if I want to access a resource using a non-Qt function. For example, I may have a .txt or .csv file with some application data that I want to accessing using ifstream. It doesn't seem to work to use the ": ..." syntax in place of a filename for non-Qt functions and classes. Is there a separate workflow for packaging data used by non-Qt functions in an app?
I'm using OSX, but I would assume these issues are platform independent.
The sole purpose of the Qt resource system is to bundle data within the executable itself. If you wish not to integrate the data in the executable, then you simply must not use the resource system.
On mac, if you wish to add "data.txt" from project source to your application bundle, but not to the executable itself, add the following to your .pro file:
mac {
BUNDLE = $$OUT_PWD/$$TARGET$$quote(.app)/Contents
QMAKE_POST_LINK += ditto \"$$PWD/data.txt\" \"$$BUNDLE/Resources/\";
}
Given the above project file, use the QCoreApplication::applicationDirPath() for a path useful in getting to the file:
#include <QCoreApplication>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << QCoreApplication::applicationDirPath();
QFile data(QCoreApplication::applicationDirPath() + "/../Resources/data.txt");
if (data.open(QIODevice::ReadOnly | QIODevice::Text))
qDebug() << data.readAll();
return 0;
}
In the above example, the Resources folder has nothing to do with the Qt resource system. It's simply a naming convention in OS X application bundles. We're not using the Qt resource system here.
If you wish to use the Qt resource system and access the resource data directly and not through a QFile, the QResource class provides access to resources that are bundled in the executable.
If the code under your control insists on using ifstream for data input, then it's artificially limited and should be fixed. It should use istream instead, as that class can be backed by anything, not necessarily a file. If it's code that you don't control, you could set up the ifstream on a QLocalSocket.
You can map the constant QResource::data() to an input stream via a stream buffer.
If the resource isCompressed(), then you need to first decompress it to a temporary area. You can also disable resource compression to avoid the decompression step. You can use a whole-executable compressor like upx instead - by the time your code runs, everything will be already decompressed and ready to use.
You can copy the resource file into a temporary folder. To do this, use a QTemporaryDir which creates a temporary folder and deletes it automatically when the program is finished. To access the path of that folder, use the QTemporaryDir::path() method. Here is an example of how you can use it:
#include <QTemporaryDir> //You need to include this header
QTemporaryDir temporaryDir;
//Copy the resource file into the temporary folder
QFile::copy(":/exampleprefix/examplefile.txt", temporaryDir.path() + "/examplefile.txt");
//Read the file
std::ifstream fileStream(QString(temporaryDir.path() + "/examplefile.txt").toLatin1().data());
//etc
What about opening the resource file with a QFile object, wrapping this with a QDataStream object, and wrapping this with a boost::iostreams::stream object, which derives from a specialization of std::basic_istream? Sounds complicated, but does not need too many lines of code, see this answer.
In the application that I am developing (using C++ and Qt), I am using QApplication::applicationDirPath() to access some resources, with respect of the application's path.
As an example, since I want to open a HTML manual from the application, I act this way:
void MainWindow::on_actionHelp_triggered()
{
QString link = QApplication::applicationDirPath() + "/Guide/guide.html";
bool r = QDesktopServices::openUrl(QUrl::fromLocalFile(link));
}
This snippet works if the project's structure presents the path "ProjectName/bin/Release/Guide/guide.html" (since the .exe file is in "ProjectName/bin/Release/AppName.exe").
But what can I do to refer to a higher-directory-level resource? As an example, I wish my HTML file to be in "ProjectName/data/Guide/guide.html". But this way, it seems not possible to compose the path in the way I'm acting.
EDIT: After #olive's comment, I wish to clarify a thing:
"Why am I not using '../'?"
Because it won't work from Visual Studio, where I am massively launch the application to test it. From VS, in fact, I shall use "../data/Guide/guide.html", when "from the outside", I'd have to do "../../data/Guide/guide.html".
That's why (I think) QApplication::applicationDirPath() exists. However, I am not an expert, so don't blame me and correct any eventual mistake of mine, please!
Just use ... QApplication::applicationDirPath() + "/../../data/Guide/guide.html" is perfectly valid path!
Of course there is another problem. When the application is installed, the relative path will probably be different again. You either need to configure the paths in visual studio so that the relative path works both during development and after deployment, or you need to detect the layout.
I wonder how to copy file that is embeded into app qrc into fs? Stuff like
QFile::copy("qrc:/assets/files/my.file" , "C:/my.file");
seems not to work. Why and how to make it to?
You don't need the qrc, resources start with a :
eg QFile myFile(":/data/data.xml");
PS: I'm not sure how QFile treats case sensitiveness on resource filenames. For best portability you might want to make sure the case matches whatever is in your qrc file.