MistyD
MistyD

Reputation: 17233

Qt : Avoid Rebuilding Applications incase strings change

I wanted to know what my options are for storing strings in a QT application. One of my major requirements in not re-building the entire project or any file in-case one string changes and also have all the strings in one place.In short I would like to have the strings in one place and extract them during Application startup

Upvotes: 0

Views: 487

Answers (4)

phyatt
phyatt

Reputation: 19122

I've used all of the elements talked about in above answers.

XML, JSON, QSettings w/ Ini files, tr()

All of them can do it just fine. I've put together some notes on the different options:

QTranslator

Qt Linguist and the tr() tags are designed to take your stock language and translate it into another language. Keeping track of multiple versions of the english translation and modifying/releasing without Qt Linguist is almost impossible. Qt Linguist is required to "release" your translations and convert them from a TS file (translation source) to an optimized QM file.

The QM file format is a compact binary format that is used by the localized application. It provides extremely fast lookups for translations.

Here is what using a translation file looks like:

 QTranslator translator;
 translator.load("hellotr_la");
 app.installTranslator(&translator);

http://qt-project.org/doc/qt-4.8/qtranslator.html#details

I think using QTranslator for a few string changes may be a weird use case, unless you are using for localizing your program. But like the docs say, it is optimized for very fast look ups of string replacements.

QXMLStreamReader

The stream reader is "recommended" way to access XML files, or at least with better support. You write your own files for organizing it, or you write code to generate the XML.

<STRING_1>Some string</STRING_1>

Here is what it looks like to navigate into xml.

QXmlStreamReader xml;
...
while (!xml.atEnd()) {
      xml.readNext();
      ... // do processing
}
if (xml.hasError()) {
      ... // do error handling
}

XML is very similar to Json, but with larger files and the start and end tags are longer. There are a lot more stock readers out there for XML. It is also a lot more human readable in many cases because so many people know html and they are very similar.

QJsonDocument

The JSON suppport in Qt 5 looks really good. I haven't built a project with it quite yet It is as easy as it looks, and as far as accessing and setting, it looks just like using a dictionary or a map or a vector.

UPDATE: You just pass around a pointer into your QJsonDocument or your QJsonObject or your QJsonArray as you are navigating deeper or appending more onto your Json file. And when you are done you can save it as a binary file, or as a clear text, human readable file, with proper indentation and everything!

How to create/read/write JSon files in Qt5

Json seems to be turning into the replacement for XML for many people. I like the example of using Json to save and load the state of a role playing game.

http://qt-project.org/doc/qt-5/qtcore-savegame-example.html

QSettings

QSettings is one of my favorites, just because it has been supported for so long, and it is how most persistent settings should be saved and accessed.

When I use it, to take advantage of the defaults and fall back mechanisms, I put this in my main.cpp:

 QCoreApplication::setOrganizationName("MySoft");
 QCoreApplication::setOrganizationDomain("mysoft.com");
 QCoreApplication::setApplicationName("Star Runner");

And because I sometimes find a need to edit these setting by hand in windows, I use the Ini format.

QSettings::setDefaultFormat(QSettings::IniFormat); // also in main.cpp

Then when I deploy my exe, and I want to have particular value loaded instead of the hardcoded defaults, the installer drops the main fallback into

C:/ProgramData/MySoft/Star Runner.ini

And when the program saves a change at runtime, it gets saved to:

C:/Users/<username>/AppData/Roaming/MySoft/Star Runner.ini

And then throughout my program if I need to get a setting or set a setting, it takes 3 lines of code or less.

// setting the value
QSettings s;
s.setValue("Strings/string_1", "new string");


// getting the value
QString str;

QSettings s;
str = s.value("Strings/string_1", "default string").toString();

And here is what your ini file would look like:

[Strings]
string_1=default string

QSettings is the way to go if you are storing a few strings you want to change on deployment or at runtime. (or if a checkbox is now checked, or your window size and position, or the recent files list or whatever).

QSettings has been optimized quite a bit and is well thought out. The ini support is awesome, with the exception that it sometimes reorders groups and keys (usually alphabetically), and it may drop any comments you put in it. I think ini comments are either started with a ; or a #.

Hope that helps.

Upvotes: 3

It is simple: Store your volatile strings in QSettings http://qt-project.org/doc/qt-4.8/qsettings.html (you can use ini files or registry) or an XML file which will make you application configurable.

Edit: Well, after thinking about it a few more minutes, Guilherme's comment is right. QSettings will need to be initialized somehow (either manually or from some default values in your code)... and to be honest manual editing registry to change a few strings is not the brightest idea. So I conclude that XML or JSON is definitely better. It has advantages, for example you can keep several config files which allow you for switching languages at runtime etc.

Upvotes: 1

Dmitry Markin
Dmitry Markin

Reputation: 1205

Another possible solution is to replace all strings with default ones inside tr() calls and use Qt Linguist to manage all the strings.

You'll also be able to load all the "translations" from external .qm file on startup.

Upvotes: 2

Devolus
Devolus

Reputation: 22094

One way to do this would be to put it in a shared library. This way you can only recompile the shared library, but not the whole project. Another approach would be to put it in a file or a database and load it at runtime.

And of course you have to check your include dependencies. If you are including the headers everywhere, the compiler will rebuild everything that depends on it, even if the header is not really needed.

Upvotes: 3

Related Questions