[SOLVED] QSettings switch between file and registry



  • Hey there

    I'm trying to set up a function which saves some settings with help of the QSettings class. It should have the possiblity to save these settings either into the windows user registry or into an INI-File which should be saved in the directory defined by the user.

    So what I know by now is that if I define the QSettings differently, it differs where theses settings are going to be saved.

    @QSettings s;@

    Like this they're saved in the regstry.

    @QSettings s(directory, QSettings::IniFormat);@

    In this way, they're saved into an INI-File at "directory".

    Now, to avoid to write the exact same code twice there should be a short differentiation at the beginning of the function.

    First I thought of something like this:

    @writeSettings(QString dir)
    {
    QSettings s;
    if(!dir.isEmpty) s.setPath(QSettings::IniFormat, QSettings::UserScope, dir);

    s.setValue(...);
    ...
    }@

    But this doesn't work. Then I though, this could solve the problem:

    @writeSettings(QString dir)
    {
    if(dir.isEmpty) QSettings s;
    else QSettings s(dir, QSettings::IniFormat);

    s.setValue(...);
    ...
    }@

    Then it won't determine "s" properly that at the first "s.setValue(...)" an "s is undefined" error occurs.

    Is there another way to solve this? At the moment I double up the whole function with two different parameter types to distinguish between both possibilities. And this isn't acceptable in my eyes.

    Thx for any help!



  • Hi luggi,

    First some comments. I personally dislike your one-line coding convention and, if you're new to C++, I suggest you consider "expanding" your code for easier legibility. Part of the reason I say that is that the following issue would have been much easier to spot:

    [quote author="luggi" date="1366547708"]
    @writeSettings(QString dir)
    {
    if(dir.isEmpty) QSettings s;
    else QSettings s(dir, QSettings::IniFormat);

    s.setValue(...);
    ...
    }@

    Then it won't determine "s" properly that at the first "s.setValue(...)" an "s is undefined" error occurs.[/quote]

    Had you written it like this:

    @writeSettings(QString dir)
    {
    if(dir.isEmpty)
    {
    QSettings s;
    }
    else
    {
    QSettings s(dir, QSettings::IniFormat);
    }

    s.setValue(...);
    ...
    }@

    you would have noticed that each of your QSettings variables are defined locally and by the time you get to "setValue", both are out of scope.

    I haven't tested your code, but the issue you're having with "setPath" may well be related to the fact that it is a static function (but I might be wrong here).

    An alternative for your particular situation could be to use compiler directives, something like:

    @#if defined(Q_OS_WIN32)
    QSettings s;
    #elif defined(Q_OS_UNIX)
    QSettings s(dir, otherStuff);
    #endif@

    However, don't just take my word for it. I'm not a QSettings expert so someone might very well come around and prove me wrong :)



  • Hi goblincoding

    Let's say I'm not new to C++ but I'm also no professional. I know that the one line convention isn't really accepted by the majority, but in my opinion I think there are several structures where it helps the compress the code a bit better by still having an acceptable overview. Anyway, as you said, I'm going to stick to a proper presentation.

    So, to you suggested solution. I think these pre-processor commands aren’t of use for my function as they’re only executed whilst compiling. But my function needs to distinguish on runtime if the settings should be saved into the registry or to a file. I’m trying to solve this over the given parameter of the function. If I want to save the settings to the registry I call

    @writeSettings(“”);@

    This results in an empty “dir” string, so the settings should be saved to the registry. If I call the same function with a valid string, the settings should be saved into an INI-file at this directory.
    But you're right, I’m not able to declare the variable local inside the if-statement and access it from the outside. But to this topic I have quite an interesting question. How would it be possible to pass a variable which is declared inside an if-statement to the rest of the function?
    I found a solution with this way:

    @
    void writeSettings(QString dir)
    {
    if(dir.isEmpty())
    {
    QSettings s;
    writeSettings(&s);
    }
    else
    {
    QSettings s(dir, QSettings::IniFormat);
    writeSettings(&s);
    }
    }
    @

    And this calls the overloaded function:

    @void TrailSim::writeSettings(QSettings *s)@

    That works but it is still a bit of a hack in my eyes.



  • Hi again luggi

    I'm sorry, I misunderstood your original post. As soon as you mentioned INI files, I assumed that you'd need to write to registry (on Windows) in one case and to INI (on Linux) for the next.

    It seems to me as if the way QSettings was designed will restrict you to your current working solution as I can't see any way to set the file name after construction. I also think your solution is pretty neat within the QSettings confines so I wouldn't be too worried about it if I were you :)

    To answer your last question, there is no way you can make a stack variable declared within your if{}else{} blocks accessible to the larger scope of the function.



  • Ok, thx for the support. As the problem is more or less solved, I'm going to set the thread to solved.

    If somebody is still dropping in at a time, I have another not that important but also interesting question. Is there a QSettings function which just saves all available properties of every object in your application and another one that reads all these properties back? That would ease up the state reload at application start.



  • Do you mean state and geometry settings? If yes, then you can do something like this in your main window class:

    @
    void MainWindow::readSettings()
    {
    QSettings settings( ORGANISATION, APPLICATION );
    restoreGeometry( settings.value( "geometry" ).toByteArray() );
    restoreState( settings.value( "windowState" ).toByteArray() );

    void MainWindow::writeSettings()
    {
    QSettings settings( ORGANISATION, APPLICATION );
    settings.setValue( "geometry", saveGeometry() );
    settings.setValue( "windowState", saveState() );
    }
    @



  • Not exactly, but these function are also useful, did it until now by move() und resize() functions. What I meant is e.g. you have ah QComboBox. This box holds a value and this value is deposited in the "value" property of that QComboBox. The user is able to change this value and I want the last value to be reloaded on the next program start.

    As I learned it, you save the value via QSettings to the registry and load it back at the next program start. That's easy and nice, but if I have an application with thousands of values, checked states etc. this starts to get a bit exhausting as you have to track every property you need to save and reload.

    So a function that just gathers every property available from every object and saves it to the registry, even if it isn't necessary and does the same on application start the other way round. That would prevent to do this with every property on it's own.



  • You could allocate the QSettings object on the heap.
    @
    void writeSettings(QString dir)
    {
    QSettings* s;
    if(dir.isEmpty())
    {
    s = new QSettings(this);
    }
    else
    {
    s = new QSettings(dir, QSettings::IniFormat, this);
    }
    writeSettings(s);
    }
    @



  • Absolutely, thx!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.