PDA

View Full Version : QSettings dont save updated variables by QML



Bedopies
11th May 2019, 22:52
Hello, I have an app where user can change a variables - delays, hotkeys etc. I do the "config saver" but it recieve "old" (not updated) variables. "Variable check" in same class working, but in other class shows others.



void Building::setWindowName(QString value){
connect(this, SIGNAL (textChanged(QString)), this, SLOT(setWindowName(QString)));
sett.windowName = value;
sett.windowID = (const wchar_t*) sett.windowName.utf16();
qDebug() << "windowName " << sett.windowName; //Shows updated
}




class Settings : public QObject
{
Q_OBJECT

public:
explicit Settings(QObject *parent = nullptr);
QSettings* sett;

int toggleButton=0x52;
int btoggleButton=0x52;// r
int inventoryKey=0x45; // e
int minCpsDelay = 10;
int maxCpsDelay = 15;

QString windowName = "Minecraft 1.8.8 (Blazingpack.pl)";
LPCWSTR windowID = (const wchar_t*) windowName.utf16();




void Settings::clickcheck()
{
qDebug() << windowName; //Showed old - not updated variable.
}



I just want to save some data from different classes.

anda_skoa
12th May 2019, 10:50
Are you checking the values on the same object?

I.e. is the Settings instance of your first code snippet the same as the one from the last snippet?

Cheers,
_

Bedopies
12th May 2019, 13:37
Are you checking the values on the same object?
_

In my opinion - yes, because I try to change sett.windowName what is declared in Settings class.



I.e. is the Settings instance of your first code snippet the same as the one from the last snippet?
Cheers,
_

I dont understand question. In first code snippet I want to set Setting's windowName from Building class.
In 2nd snippet, it shows this variable in Settings class.
In 3rd snippet, I try to show this changed variable.

Idk, worth to do it like this? Keep this all "user-changable" variables in one class for QSettings only.

anda_skoa
12th May 2019, 15:13
I dont understand question.

Your first code snippet suggests that the Building class has a member called "sett".

Do you call the "clickcheck()" method on that "sett" object?
Or are you accidentally calling it on a different Settings object?

Cheers,
_

Bedopies
12th May 2019, 15:43
I called Clickcheck() from QML with


Settings.clickcheck();

and when I pressed mouse area this show me old variable.

There's another code with same "error":


#ifndef KEPPOXD_H
#define KEPPOXD_H

#include <QObject>
#include <QDebug>

class keppoxd : public QObject
{
Q_OBJECT
public:
explicit keppoxd(QObject *parent = nullptr);
QString name = "old";

signals:
void textChanged(QString);

public slots:
void setWindowName(QString value);
void test();
};

#endif // KEPPOXD_H



#ifndef SIEMA_H
#define SIEMA_H

#include <QObject>
#include <QDebug>
#include <keppoxd.h>


class siema : public QObject
{
Q_OBJECT
public:
explicit siema(QObject *parent = nullptr);
keppoxd keppo;

signals:
void textChanged(QString);

public slots:
void setWindowName(QString value);

};

#endif // SIEMA_H




#include "keppoxd.h"

keppoxd::keppoxd(QObject *parent) : QObject(parent)
{

}

void keppoxd::setWindowName(QString value)
{
connect(this, SIGNAL (textChanged(QString)), this, SLOT(setWindowName(QString)));
name = value;
qDebug() << name;
}

void keppoxd::test()
{
qDebug() << "keppo test " << name;
}





#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include <keppoxd.h>
#include <siema.h>
#include <QQmlContext>
#include <QQmlApplicationEngine>

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

QCoreApplication::setAttribute(Qt::AA_EnableHighDp iScaling);

QGuiApplication app(argc, argv);
//QSettings* settings;

/*if(QFileInfo::exists(QDir::currentPath() + "/my_config_file.ini")){
qDebug() << "istnieje";
}
else{
qDebug() << "nie istnieje";

settings = new QSettings(QDir::currentPath() + "/my_config_file.ini", QSettings::IniFormat);
settings->setValue("test", "value");
settings->setValue("Button", 1);
settings->sync();
} */


siema siema;
keppoxd keppo;

QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);


QQmlContext *ctx = engine.rootContext();

ctx->setContextProperty("Siema", &siema);
ctx->setContextProperty("Keppo", &keppo);

return app.exec();
}




#include "siema.h"

siema::siema(QObject *parent) : QObject(parent)
{

}

void siema::setWindowName(QString value)
{
connect(this, SIGNAL (textChanged(QString)), this, SLOT(setWindowName(QString)));
keppo.name = value;
qDebug() << keppo.name;
}




import QtQuick 2.9
import QtQuick.Window 2.2

Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")

TextInput {
id: textInput
x: 48
y: 58
width: 80
height: 20
text: qsTr("Text Input")
font.pixelSize: 12
onTextEdited:{
Siema.setWindowName(textInput.text);
Keppo.test();
}
}

Rectangle {
id: rectangle
x: 276
y: 41
width: 200
height: 200
color: "#e30a0a"

MouseArea {
id: mouseArea
x: 0
y: 0
width: 200
height: 200
onClicked:{
Siema.setWindowName(textInput.text);
Keppo.test();
}
}
}
}


Log:


istnieje
"Text Input"
keppo test "old"
"Text Input"
keppo test "old"
"Text Ixnput"
keppo test "old"
"Text Ixdnput"
keppo test "old"
"Text Ixdnput"
keppo test "old"
"Text Ixdnput"
keppo test "old"
"Text Ixdnput"
keppo test "old"

d_stranz
12th May 2019, 18:07
void keppoxd::setWindowName(QString value)
{
connect(this, SIGNAL (textChanged(QString)), this, SLOT(setWindowName(QString)));
name = value;
qDebug() << name;
}

void siema::setWindowName(QString value)
{
connect(this, SIGNAL (textChanged(QString)), this, SLOT(setWindowName(QString)));
keppo.name = value;
qDebug() << keppo.name;
}

I don't think you understand how signals and slots work. You should be calling connect() in the constructor for these classes, not in the slot. I see that the methods are being called from QML, but the connect() calls are in the wrong place. Put each of these connect() calls into the constructors for their classes.

The next problem is that I do not see where you are emitting the "textChanged()" signals in either of these classes. Even if you have signals and slots connected, if you never emit the textChanged() signal, the slot never gets executed.

The third problem with your current code is that if you put the connect() statements in the slots, each time the slot is executed there is another connection made, so if the textChanged() signal ever does get emitted you will get repeated execution of the slot (and a another connection) each time the slot is called.

And the final problem: you have two instances of the class "keppoxd", both of them named "keppo". One of them is a member variable of the class "siema", the other one is an automatic variable in your "main" function. You have told QML to use the one in the main() function as the context property "Keppo". So when you call siema.setWindowName() from QML it is setting the value contained in siema's keppo variable, but the QML call to keppo.test() is displaying the value stored in the keppo instance in main(), which never changes from the default value "old".

Bedopies
12th May 2019, 19:55
So to fix my problem I have to rename "siema" and "keppo" declarations in main?

I now have sth like this, but still not working.



#ifndef KEPPOXD_H
#define KEPPOXD_H

#include <QObject>
#include <QDebug>
#include <siema.h>

class keppoxd : public QObject
{
Q_OBJECT
public:
explicit keppoxd(QObject *parent = nullptr);
siema siema;

signals:
void textChanged(QString);
public slots:
void setWindowName(QString value);

};

#endif // KEPPOXD_H




#ifndef SIEMA_H
#define SIEMA_H

#include <QObject>
#include <QDebug>


class siema : public QObject
{
Q_OBJECT
public:
explicit siema(QObject *parent = nullptr);
QString name = "old";

signals:

public slots:
void setWindowName(QString value);
void check();

};

#endif // SIEMA_H




#include "keppoxd.h"

keppoxd::keppoxd(QObject *parent) : QObject(parent)
{
connect(this, SIGNAL (textChanged(QString)), &siema, SLOT(setWindowName(QString)));
}

void keppoxd::setWindowName(QString value)
{
siema.name = value;
qDebug() << "siema.name value from keppo class " << siema.name;
emit textChanged(value);
}





#include "siema.h"

siema::siema(QObject *parent) : QObject(parent)
{

}

void siema::setWindowName(QString value)
{
name = value;
}

void siema::check()
{
qDebug() << "siema value " << name;
}




#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include <keppoxd.h>
#include <siema.h>
#include <QQmlContext>
#include <QQmlApplicationEngine>

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

QCoreApplication::setAttribute(Qt::AA_EnableHighDp iScaling);

QGuiApplication app(argc, argv);
//QSettings* settings;

/*if(QFileInfo::exists(QDir::currentPath() + "/my_config_file.ini")){
qDebug() << "istnieje";
}
else{
qDebug() << "nie istnieje";

settings = new QSettings(QDir::currentPath() + "/my_config_file.ini", QSettings::IniFormat);
settings->setValue("test", "value");
settings->setValue("Button", 1);
settings->sync();
} */


siema siemaqml;
keppoxd keppoqml;

QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);


QQmlContext *ctx = engine.rootContext();

ctx->setContextProperty("Siema", &siemaqml);
ctx->setContextProperty("Keppo", &keppoqml);

return app.exec();
}




import QtQuick 2.9
import QtQuick.Window 2.2

Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")

TextInput {
id: textInput
x: 48
y: 58
width: 80
height: 20
text: qsTr("Text Input")
font.pixelSize: 12
onTextEdited:{
Keppo.setWindowName(textInput.text);
Siema.check();
}
}

Rectangle {
id: rectangle
x: 276
y: 41
width: 200
height: 200
color: "#e30a0a"

MouseArea {
id: mouseArea
x: 0
y: 0
width: 200
height: 200
onClicked:{
Keppo.setWindowName(textInput.text);
Siema.check();
}
}
}
}

anda_skoa
13th May 2019, 08:46
I called Clickcheck() from QML with


Settings.clickcheck();

and when I pressed mouse area this show me old variable.

Without knowing how you exposed the C++ object to QML my guess is that this is a different instance of the Settings class than the one inside Building.

So you are very likely doing this
- setting the value on Building.sett
- checking the value on Setting

Obviously the latter object won't have the value of the former.





onTextEdited:{
Siema.setWindowName(textInput.text);
Keppo.test();
}



That makes no sense.

You are calling Siema.setWindowName(), which changes a value in the Siema object.
But then you are calling the test() method on the Keppo object?

This should probably be


onTextEdited:{
Siema.setWindowName(textInput.text);
Siema.test();
}


Cheers,
_

Bedopies
13th May 2019, 12:13
Fixed by:



class keppoxd : public QObject
{
Q_OBJECT
public:
explicit keppoxd(QObject *parent = nullptr);
siema *siema;
...

int main(){
siema siema;
keppoxd keppo;

keppo.siema = &siema;
...