QSettings can't create .ini, but can read it O_o



  • Hello everyone,
    today I got in troubles with the QSettings gang (don't mess up with them) and they decided to annoy me using this evil trick:
    .h
    @class Clown : public QWidget
    ...
    protected:
    QSettings *settings;@

    .cpp
    @Clown::Clown(QWidget *parent) :
    QWidget(parent)
    {
    settings = new QSettings("SATAN_666.ini", QSettings::IniFormat);
    settings->sync();
    //Later
    QObject::connect(but,SIGNAL(clicked()),this,SLOT(PlusOne()));
    }

    void Clown::PlusOne()
    {
    settings->setValue("clics", settings->value("clics").toInt()+1);
    // and other stuff incuding the clics key display, works fine
    }@

    So here's the deal:
    The program starts, I use the PlusOne slot, the values display, everytime with +1 everytime it's called, so it basically works but HOW THE HELL does it work, knowing that the .ini file hasn't been created?
    If I close the program and open it up again, it will start back to 0...
    How can I force the creation of this file?
    I used this part of code in another program, and it perfectly works so why not with this one?
    Thanks


  • Lifetime Qt Champion

    Hi,

    You are missing the organization and application name when building your settings.

    Have a look at "the basic usage documentation":http://qt-project.org/doc/qt-4.8/qsettings.html#basic-usage

    It shows how you should use QSettings with your application (or at least how I understand you want to use it)

    Hope it helps



  • Which OS do you use?



  • I use Windows 7 64bits, thanks for your answer SGalst, but this still doesn't work :(


  • Lifetime Qt Champion

    How does your code look like now ?



  • This is the whole code so basically you don't have to read that all:
    main
    @#include <QWidget>
    #include <QApplication>
    #include "Clown.h"

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);

    app.setApplicationName("Clic le Clown");
    app.setApplicationVersion("1.0");
    app.setOrganizationName("Paul Combaldieu");
    app.setOrganizationDomain("NoDomain");
    
    Clown clown;
    clown.show();
    
    return app.exec();
    

    }
    @

    .h
    @#ifndef CLOWN_H
    #define CLOWN_H

    #include <QWidget>
    #include <QLCDNumber>
    #include <QSettings>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QSound>

    class Clown : public QWidget
    {
    Q_OBJECT
    public:
    explicit Clown(QWidget *parent = 0);

    signals:

    public slots:
    void PlusOne();

    protected:
    QLCDNumber *clicks;
    QSettings *settings;
    QSound *sound;

    };

    #endif // CLOWN_H
    @

    .cpp
    @#include "Clown.h"

    Clown::Clown(QWidget *parent) :
    QWidget(parent)
    {
    sound = new QSound(QString("pouet.wav"),this);
    QVBoxLayout *lay = new QVBoxLayout(this);
    settings = new QSettings("SATAN_666.ini", QSettings::IniFormat);
    settings->sync();
    clicks = new QLCDNumber;
    QPushButton *but = new QPushButton;
    but->setIcon(QIcon("Clown.jpg"));
    but->setIconSize(QSize(200,200));

    clicks->display(settings->value("clics").toInt());
    
    lay->addWidget(clicks);
    lay->addWidget(but);
    
    setMinimumSize(300,300);
    
            QObject::connect(but,SIGNAL(clicked()),this,SLOT(PlusOne()));
    

    }

    void Clown::PlusOne()
    {
    if(!sound->isFinished())
    sound->stop();

    settings->setValue("clics", settings->value("clics").toInt()+1);
    findChild<QLCDNumber*>()->display(settings->value("clics").toInt());
    findChild<QPushButton*>()->setFocus();
    sound->play();
    

    }
    @

    I can't wait to see what you get out of that ^^


  • Lifetime Qt Champion

    Well... I must say that you are using QSettings in a rather strange fashion. If you only want to increment the QLCDValue you should rather use something like:

    @clicks->setValue(clicks->intValue() + 1);@

    There's no need for findChild since your QLCDNumber is a member variable of your class.

    If you want to store and reload the last value you should use QSettings the standard way (as shown in the doc) in the constructor and destructor of your class.



  • Hi,

    I think the ini file must be created somewhere in the locations specified by the qt's doc ... may be is worth to use an explicit path and check this out; on this issue I may say from experience that QSettings constructor on some platform does not ceate the file if it doesn't exist ( i.e. linux embedded), but by using setValue the creation will be forced ...

    now, from your app's logic I think you get what it is supposed to do:
    you call setValue just before any value reading so it wites 0 again in file and then is obvious ...

    and for storing you don't necessarily need to call sync() just update the value in memory as pointed out above and call setValue to store it and let the event loop to call sync() ...

    hope this help! :)

    Cheers!



  • I have some big news for this thread:
    First I modified a bit the .cpp, but now the incrementation you suggested doesn't work, and also I am not sure about what I did in the destructor.
    Here is what it looks like:
    @#include "Clown.h"

    Clown::Clown(QWidget *parent) :
    QWidget(parent)
    {
    sound = new QSound(QString("pouet.wav"),this);
    QVBoxLayout *lay = new QVBoxLayout(this);
    settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,"Paul Combaldieu", "Clic Le Clown");
    settings->setPath(QSettings::IniFormat,QSettings::UserScope,(QDir::currentPath() + QString("/test.ini")));
    clicks = new QLCDNumber;
    QPushButton *but = new QPushButton;
    but->setIcon(QIcon("Clown.jpg"));
    but->setIconSize(QSize(200,200));

    clicks->display(settings->value("clics").toInt());
    
    lay->addWidget(clicks);
    lay->addWidget(but);
    
    setMinimumSize(300,300);
    
            QObject::connect(but,SIGNAL(clicked()),this,SLOT(PlusOne()));
    

    }

    void Clown::PlusOne()
    {
    if(!sound->isFinished())
    sound->stop();

    clicks->display(clicks->intValue()+1);
    findChild<QLCDNumber*>()->display(settings->value("clics").toInt());
    findChild<QPushButton*>()->setFocus();
    sound->play();
    

    }

    Clown::~Clown()
    {
    settings->setValue("clics",clicks->intValue());
    delete sound;
    delete clicks;
    delete findChild<QPushButton*>();
    delete findChild<QVBoxLayout*>();
    delete settings;
    }
    @

    Also, when I hit run while in Qt creator, here's what I get:
    Starting C:\Users\LOUISPAUL\Projets\Qt\Clic_Le_Clown-build-desktop\debug\Clic_Le_Clown.exe...
    HFunc_OpenSCManagerAW called...
    HFunc_OpenServiceW (h=ee070000, name=AudioSrv, desiredAccess=5)

    • got h=6b0b18
      HFunc_CloseServiceHandle, h=6b0b18 (bValid=1)
      HFunc_CloseServiceHandle, h=ee070000 (bValid=0)
      HFunc_OpenSCManagerAW called...
      HFunc_OpenServiceW (h=ee070000, name=AudioSrv, desiredAccess=4)
    • got h=6b0b18
      HFunc_NotifyServiceStatusChangeW, h=6b0b18
      HFunc_CloseServiceHandle, h=ee070000 (bValid=0)
      HFunc_CloseServiceHandle, h=6b0b18 (bValid=1)
      C:\Users\LOUISPAUL\Projets\Qt\Clic_Le_Clown-build-desktop\debug\Clic_Le_Clown.exe terminated with code 0

    Is that normal?
    Thanks



  • Hi,

    first, I did not see you read value in constructor ... but, except that you still have mistakes in code and no, you have not done what SGaist said:

    • stop using findChild whenever and everywhere :) especially when you have access to a class members and you have just created them
      this line:
      @ findChild<QLCDNumber*>()->display(settings->value("clics").toInt());@
      is awkward: findChild<QLCDNumber*>()=clicks object , and settings->value read out again an unmodified value

    anyway delete it at all :)

    if you need dynamic storage call setValue after

    @clicks->display(clicks->intValue()+1);@

    but will slow the code execution ... setValue in destructor is enough as it's been said already



  • Ok thank you a lot for these useful pieces of advice,I removed the findchilds and everything , but actually, what do you mean in "read values"? I tried out something: adding a setValue and Value in the constructor, but nothing happens
    Thanks for your patience, many thanks..


  • Lifetime Qt Champion

    Don't delete widgets/layout like that in your constructor. It's already all managed for you by Qt.

    What do you mean by nothing happens ?



  • Hmm destructor you mean, right?
    I mean by nothing happens that there's still no .ini file, I qDebugged the place where the file was supposed to be created, but there's still nothing..



  • Wait what!! I found something awesome: I disabled Avast! and it started working!! Awesome you will say, but look at that:

    @settings->setPath(QSettings::IniFormat,QSettings::UserScope,(QDir::currentPath() + QString("/test.ini")));
    //.....
    qDebug() << (QDir::currentPath() + QString("/test.ini"));@

    But still no test.ini ?! Where the heck is it?
    If you wanna know where it is.. "C:/Users/LOUISPAUL/Projets/Qt/Clic_Le_Clown-build-desktop/test.ini"
    here you go..


  • Lifetime Qt Champion

    Where were you looking before ?

    Since you use QDir::currentPath() the file would logically be created where the executable exists.

    As for why Avast is interfering... Good question...



  • Today everything changed:

    • I found out that the program starts up with a value of 15
    • I can't write in the .ini
    • The ini is still missing
    • I updated my code, made sure all antiviruses are disabled

    @#include "Clown.h"
    #include <QDebug>

    Clown::Clown(QWidget *parent) :
    QWidget(parent)
    {
    sound = new QSound(QString("pouet.wav"),this);
    QVBoxLayout *lay = new QVBoxLayout(this);
    settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,"Paul Combaldieu", "Clic Le Clown");
    settings->setPath(QSettings::IniFormat,QSettings::UserScope,(QDir::currentPath() + QString("/test.ini")));

    // settings->setValue("test", 9000);
    // settings->value("test"); //does nothing
    // settings->remove(QString("test"));

    qDebug() << (QDir::currentPath() + QString("/test.ini"));
    qDebug() << settings->value("clics").toInt();
    
    clicks = new QLCDNumber;
    clicks->setStyleSheet(QString("color: red;"));
    QPushButton *but = new QPushButton;
    but->setIcon(QIcon("Clown.jpg"));
    but->setIconSize(QSize(200,200));
    
    clicks->display(settings->value("clics").toInt());
    
    lay->addWidget(clicks);
    lay->addWidget(but);
    setLayout(lay);
    
    setMinimumSize(300,300);
    
            QObject::connect(but,SIGNAL(clicked()),this,SLOT(PlusOne()));
    

    }

    void Clown::PlusOne()
    {
    if(!sound->isFinished())
    sound->stop();

    clicks->display(clicks->intValue()+1);
    findChild<QPushButton*>()->setFocus();
    sound->play();
    

    }

    Clown::~Clown()
    {
    qDebug() << "In destructor, writing " << clicks->intValue() << "in ini file.";
    settings->setValue("clics",clicks->intValue());
    }
    @

    Log:
    @Starting de C:\Users\LOUISPAUL\Projets\Qt\Clic_Le_Clown-build-desktop\debug\Clic_Le_Clown.exe...
    "C:/Users/LOUISPAUL/Projets/Qt/Clic_Le_Clown-build-desktop/test.ini"
    15
    In destructor, writing 23 in ini file.
    C:\Users\LOUISPAUL\Projets\Qt\Clic_Le_Clown-build-desktop\debug\Clic_Le_Clown.exe terminated code 0

    Starting C:\Users\LOUISPAUL\Projets\Qt\Clic_Le_Clown-build-desktop\debug\Clic_Le_Clown.exe...
    "C:/Users/LOUISPAUL/Projets/Qt/Clic_Le_Clown-build-desktop/test.ini"
    15
    In destructor, writing 17 in ini file.
    C:\Users\LOUISPAUL\Projets\Qt\Clic_Le_Clown-build-desktop\debug\Clic_Le_Clown.exe terminated with code 0@

    Note that in the path, the /debug folder is missing before test.ini


  • Lifetime Qt Champion

    QDir::currentPath() returns the path of the directory containing the executable so it's points to the folder containing debug.

    You don't delete settings in your destructor so it is not properly destroyed.



  • Wait so does it mean that I don't have to delete my widgets in the destructor, but I have to delete the QSettings? Why?

    Edit
    Just found out something:
    @settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,"Paul Combaldieu", "Clic Le Clown");
    settings->setPath(QSettings::IniFormat,QSettings::UserScope,(QDir::currentPath() + QString("test.ini")));
    //Later
    qDebug() << settings->fileName();@

    filename: "C:/Users/LOUISPAUL/AppData/Roaming/Paul Combaldieu/Clic Le Clown.ini"

    Wtf?


  • Lifetime Qt Champion

    The widgets inside your Clown widget become children of Clown once you put them in the layout that is also a child of Clown. Your settings variable is not a child so you have to delete it manually.

    setPath is a static function that sets the path (folder) where the files of format IniFormat will be stored. Since you call it after having created your settings object it wont affect it.

    The file name and location are build based on what you give in the constructor. "Paul Combaldieu" as the company and "Clic Le Clown" as the application name.

    The settings files are generally stored in the "application name" folder found in the "company name" folder.


Log in to reply
 

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