Qt - Add files to project - qt

I'm making an application part of which is reading from an XML which stores some preferences. However, whenever I build the project, all the sources get copied but the preferences file does not! I have added the following to the .pro file -
RESOURCES += rsc.qrc
And my rsc.qrc contains
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>data/preferences.xml</file>
<file>data/gamedata.xml</file>
</qresource>
</RCC>
Now whenever I try to open preferences.xml
QFile preferences(":/data/preferences.xml");
if(!preferences.exists()){
preferences.open(QFile::WriteOnly);
preferences.write("abc");
qDebug() << "Written";
}
else {
qDebug() << "File exists";
}
Absolutely nothing gets printed and even the rest of the application stops working.

You don't use the resource part correctly in your example.
It will most likely not work because you try to write to a resource that is embedded into your executable after you have build your application. Reading is fine, but writing can't work by definition.
If you want a editable setting files, you have to distribute them along with your executable, or use a different method for reading/writing your settings like QSettings.
However using QSettings also means, that you will need to configure all your default settings in your loading function in case the values do not exist if you use the default configuration. Meaning you use registry on windows.
You have the option to force the use of a INI file format in the constructor of QSettings, this can make sense if you want to provide a default settings INI file instead of your xml files.
In case you want to store more complex data a xml file might be needed anyway, so if you want to stick with that you will need a way to copy your setting files to your build path. This can be done within your pro file with QMAKE_POST_LINK.
Example:
COPY_CMD = "$$PWD\\data\\preferences.xml $$OUT_PWD\\release\\data\\preferences.xml"
COPY_CMD = $${QMAKE_COPY} $$replace( COPY_CMD, "/", "\\" ) $$escape_expand( \\n\\t )
QMAKE_POST_LINK += $$COPY_CMD

Related

Premake (lua) pch create /Yc Visual Studio

In the premake lua script for my solution. How do i set it to create "/Yc" the phc instead of being set to use "/Yu" on first initialisation.
I have searched the online documentation and tried other help sites. I can't find any help.
I assume it's a build option but have tried buildoptions { "/Yc" }
Some help would be much appritiated?
The solution was to set the correct path to the source file.
premake5.lua
pchheader "awepch.h"
pchsource "%{prj.name}/Src/awepch.cpp" // this is where the source file is located on disk
* Also it is mandatory that you use the correct case for the characters. If you use "pch.h" for a file name on disk that must be the file name in this section of your "premake5.lua" script
Sorry to take so long to deliver the answer :)
you need to specify
pchheader('StdAfx.h')
and
pchsource('StdAfx.cpp')
For the current version of premake v5. 0.0-beta1, you must do the following in order for the precompiled header to work across all IDEs (especially for Visual Studio):
Put both pch.h and pch.cpp under the root directory of your project (not solution/workspace).
Set the exact name (not a path) of the pch.h to pchheader().
Set the full path of pch.cpp relative to premake5.lua script in pchsource(). This is IMPORTANT. I don't know why, but if you do not specify the full relative path, then premake will Use (/Yu) (use precompiled header) to the phc.cpp instead of Create (/Yc) (create precompiled header), which results in not creating the precompiled header in Visual Studio.
Include the directory where pch.h and pch.cpp are located in includedirs()
#include "pch.h" IN EVERY .cpp file in your project, IN THE FIRST LINE of each .cpp file. Remember: #include "pch.h", "pch.h" must be excactly the same as the string you set in pchheader() in your premake5.lua script.
If you have .c files, you MUST rename them to .cpp instead, otherwise Visual Studio will complain about using a precompiled header that was compiled using a c++ compiler.
I know it's overcomplicated but this is how it is.
Example:
project "LearnGL"
location "Projects/LearnGL/"
kind "ConsoleApp"
language "C++"
targetdir "builds/"
objdir "obj/%{prj.name}_%{cfg.shortname}"
pchheader "pch.h" --Do not use paths here. Use directly the header file name
pchsource "Projects/LearnGL/src/pch.cpp" --Full path MUST be specified relative to the premake5.lua (this) script.
files {
"Projects/LearnGL/src/**.h",
"Projects/LearnGL/src/**.hpp",
"Projects/LearnGL/src/**.cpp"
}
includedirs {
"Projects/LearnGL/src/", --This is where pch.h and pch.cpp are located.
"Projects/LearnGL/src/external/glad/include/",
"Projects/LearnGL/src/external/stb_image/include/",
"External/glfw/include/",
"External/spdlog/include/"
}

Pre-compile QML files under Qt Quick Controls

I am importing 2 QML files that come with Qt Controls - ScrollBar.qml and Button.qml in my project. I pre-compile all .qml files that I wrote to reduce application launch time. Is there a way to pre-compile these 2 QML files that come as part of the package?
I tried to remove these files from the qml/QtQuick/Controls/ path and placed them in the same folder as my .qml files but it still failed to load. When I reference ScrollBar in my code, it always tries to load ScrollBar.qml from qml/QtQuick/Controls/ path.
Does any one know if it is possible to pre-compile these QMLs at all? If yes, has any one successfully done it?
Appreciate any help. Thank you.
I'm assuming that you're referring to the Qt Quick Compiler as pre-compiling. The simplest way would just be to build the entire Qt Quick Controls module with the Qt Quick Compiler.
If you need to have it within your project, you could try adding an import that contains the Qt Quick Controls import. QQmlEngine::addImportPath() says:
The newly added path will be first in the importPathList().
That statement seems to imply that order matters, and the code confirms it:
QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local);
// Search local import paths for a matching version
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin);
for (const QString &qmldirPath : qmlDirPaths) {
QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
if (!absoluteFilePath.isEmpty()) {
QString url;
const QStringRef absolutePath = absoluteFilePath.leftRef(absoluteFilePath.lastIndexOf(Slash) + 1);
if (absolutePath.at(0) == Colon)
url = QLatin1String("qrc://") + absolutePath.mid(1);
else
url = QUrl::fromLocalFile(absolutePath.toString()).toString();
QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
cache->versionMajor = vmaj;
cache->versionMinor = vmin;
cache->qmldirFilePath = absoluteFilePath;
cache->qmldirPathUrl = url;
cache->next = cacheHead;
database->qmldirCache.insert(uri, cache);
*outQmldirFilePath = absoluteFilePath;
*outQmldirPathUrl = url;
return true;
}
}
Your project structure might look something like this:
myproject/
qml/
main.qml
QtQuick/
Controls/
Button.qml
ScrollBar.qml
qmldir
In main.cpp you'd set the path to the qml directory (note that the path will be different depending on whether you're doing an in-source build or a shadow build of your project, so you may want to use a resource file to simplify things):
engine.addImportPath("path/to/qml");
Note that the controls import other types. For example, Button uses the Settings singleton, which comes from the QtQuick.Controls.Private import, so you'd need to copy that into the qml directory, too. Settings loads a certain style for the button (ButtonStyle), which could be any of the styles in this folder, depending on which style is in use.
In short, you need to copy all of the potential dependencies of the QML files you're using.

How specify file filter in QFileDialog::getExistingDirectory?

I need to choose a directory with files "*.in".
But if i use getExistingDirectory, i can't specify file filter, so i can't see files.
But i need to see ONLY "*.in" files, i could be only choose a directory, not a file.
Now i use this code:
qDebug() << QFileDialog::getExistingDirectory(this, tr("Выберите папку с файлами устройств"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
And i can't see any files in chosen directory (in dialog).
How i can do this?
You need to pass QFileDialog::DontUseNativeDialog option. From the documentation of getExistingDirectory:
On Windows and OS X, this static function will use the native file
dialog and not a QFileDialog. However, the native Windows file dialog
does not support displaying files in the directory chooser. You need
to pass DontUseNativeDialog to display files using a QFileDialog. On
Windows CE, if the device has no native file dialog, a QFileDialog
will be used.
To filter displayed files by extension you will have to do slightly more:
QFileDialog dlg(nullptr, tr("Choose Directory"));
dlg.setOptions(QFileDialog::DontUseNativeDialog | QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
dlg.setFileMode(QFileDialog::Directory);
dlg.setNameFilter(tr("Directories with device files (*.in)"));
if (dlg.exec())
qDebug() << dlg.selectedFiles();
When I tried this, the files that don't match the filter were still displayed, but in grey color (I tried on MacOS, maybe you will have more luck on Windows).
There is no standard way to prevent user from selecting a folder which contains no files matching the filter. A solution is to derive your own class from QFileDialog and override the accept function (not calling QFileDialog::accept from your override will prevent the dialog from closing).
I think it doesn't work with get-dir method. Would it be also acceptable to let the user select any of the *.in files and then getting the directory of that in-file using QFileInfo::path?
QString inFile = QFileDialog::getOpenFileName(
this,
tr( "Выберите папку с файлами устройств "
"выделив какой-либо из файлов устройств :-)"
),
lastSelectedDir,
"*.in"
);
QString dirName = QFileInfo(inFile ).absolutePath();

Qt QFileSystemWatcher on Windows

I have the following issue: I create a QFileSystemWatcher and it runs and works nicely on Linux, but no way on Windows 7. Can you spot anything in the code that might make it not to work?
Thx.
Here is the code to initialize it:
mConfigChangeWatcher = new QFileSystemWatcher();
mConfigChangeWatcher->addPath(config_file_name);
QObject::connect(mConfigChangeWatcher,
SIGNAL(fileChanged(QString)),
this,
SLOT(configFileChanged(QString)));
and this is supposed to be the slot getting the work done:
void MyClass::configFileChanged(const QString &file)
{
qDebug() << "Changed: " << file ;
}
When you check if the file is added to the watcher using QFileSystemWatcher::files() method after the first modification in the file do you get the correct list?
I was with the issue that some applications, when modifing a file, delete the old file from the system and write it again.
Note that QFileSystemWatcher stops monitoring files once they have been renamed or removed from disk, and directories once they have been removed from disk.
I was using QFileSystemWatcher to watch an image file edited by Photoshop. Somehow the file gets removed from the list of files being watched.
I had the same problem and solved it very fast.
Within the slot that manages the fileChanged signal I noted the path disappears from files(). I simply make a check and re-add it if necessary
if (! watcher_.files().contains(path))
{
watcher_.addPath(path);
}
I hope this helps
Fabio

QImage class : file loading

If I want to load file directly (QImage i1("image1.jpg");) where should I store it?
If I have to give full path of file or only short path is required?
If you don't want to worry about an image (and you are not having too much of them), consider using Qt Resources. Qt Resources will embed the image into the executable independent of the platform. The images would be pulled from the filesystem at compile time, and an IDE like Qt Creator actually helps you with that.
E.g. if you created an resource called "image" containing your file, you could reference your image by typing
QImage(":/images/image1.jpg")
If you want to use QImage as you have written in your question, then your image needs to be in your current directory. Most likely that will be the directory where your executable is stored.
Otherwise you will have to give either a relative or full path.
Use the absolution path or copying the image1.jpg to the current path.
My current path in qt creator is not same as *.exe, but its parent (debug/Release). Use the below code to find.
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Image"),
QDir::currentPath(),
tr("Image Files (*.png *.jpg *.bmp)"));

Resources