Update value in QJsonArray and write back to Json file in Qt - c++

I have a Json file to read and display on UI. Reading is fine but when I tried to update value wheelbase, code runs with no errors but it does not update the Json
Json file example
{
"$type": "SystemList",
"$values": [
{
"chassicId": 1000,
"wheelbase": 98
},
{
"chassicId": 1001,
"wheelbase": 102
}
]
}
This is the write function. What I have tried is to parse the Json file to the QJsonArray, then iterates and map with the function id parameter in order to update the wheelbase value.
void updateWheelbase(const int& id)
{
updatedWheelbase = dialog.wheelbaseInput().toDouble();
QFile file("json file path");
file.open(QIODevice::ReadOnly | QIODevice::Text);
QByteArray jsonData = file.readAll();
file.close();
QJsonDocument itemDoc = QJsonDocument::fromJson(jsonData);
QJsonObject rootObject = itemDoc.object();
QJsonArray valuesArray = rootObject.value("$values").toArray();
//get a copy of the QJsonObject
QJsonObject obj;
for (auto v: valuesArray) {
QJsonObject o = v.toObject();
if (o.value("chassicId").toInt() == id) {
obj = o;
break;
}
}
// modify the object
obj["wheelbase"] = updatedWheelbase;
int position = 0;
// erase the old instance of the object
for (auto it = valuesArray.begin(); it != valuesArray.end(); ++it) {
QJsonObject obj = (*it).toObject();
if (obj.value("chassicId").toInt() == id) {
valuesArray.erase(it);
//assign the array copy which has the object deleted
rootObject["$value"] = valuesArray;
break;
}
position++;
}
// add the modified QJsonObject
valuesArray.append(obj);
// replace the original array with the array containing our modified threshold object
itemDoc.setObject(rootObject);
file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
file.write(itemDoc.toJson());
file.close();
}

You should place rootObject["$value"] = valuesArray; after the valuesArray.append(obj);. In your example, when append obj to valuesArray, you just update valuesArray, have not update rootObject.
#include <QtWidgets/QApplication>
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
void updateWheelbase()
{
int id = 1001;
double updatedWheelbase = 1.1;
QFile file("./Debug/a.json");
file.open(QIODevice::ReadOnly | QIODevice::Text);
QByteArray jsonData = file.readAll();
file.close();
QJsonDocument itemDoc = QJsonDocument::fromJson(jsonData);
QJsonObject rootObject = itemDoc.object();
QJsonArray valuesArray = rootObject.value("$values").toArray();
//get a copy of the QJsonObject
QJsonObject obj;
for (auto v : valuesArray) {
QJsonObject o = v.toObject();
if (o.value("chassicId").toInt() == id) {
obj = o;
break;
}
}
// modify the object
obj["wheelbase"] = updatedWheelbase;
int position = 0;
// erase the old instance of the object
for (auto it = valuesArray.begin(); it != valuesArray.end(); ++it) {
QJsonObject obj = (*it).toObject();
if (obj.value("chassicId").toInt() == id) {
valuesArray.erase(it);
//assign the array copy which has the object deleted
rootObject["$values"] = valuesArray;
break;
}
position++;
}
// add the modified QJsonObject
valuesArray.append(obj);
rootObject["$values"] = valuesArray;
// replace the original array with the array containing our modified threshold object
itemDoc.setObject(rootObject);
file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
file.write(itemDoc.toJson());
file.close();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
updateWheelbase();
return a.exec();
}

Related

Converting JSON text file back to QJsonArray

I have an object that I serialize it into JSON using the code below (also see the the struct):
struct RegisterItem {
RegisterType Type = RegisterType::ReadWrite;
QString Name = QStringLiteral("REGISTER");
int Bank = 0;
int Address = 0;
int Range = 1;
int DefaultValue = 0;
int CurrentValue = 0;
int SpecialAction = REG_SPECIAL_ACTION_NONE;
};
This code converts it to json text file:
bool saveRegisterStateToFile(const QVector<RegisterWidget*>& widgets)
{
QJsonArray arr;
for(int i = 0; i < widgets.size(); i++) {
RegisterItem item = widgets[i]->registerItem();
auto data = QJsonObject({
qMakePair(QString("Address"), QJsonValue(item.Address)),
qMakePair(QString("Name"), QJsonValue(item.Name)),
qMakePair(QString("Bank"), QJsonValue(item.Bank)),
qMakePair(QString("Type"), QJsonValue(static_cast<int>(item.Type))),
qMakePair(QString("DefaultValue"), QJsonValue(item.DefaultValue)),
qMakePair(QString("SpecialAction"), QJsonValue(item.SpecialAction))
});
arr.push_back(data);
}
QFile file("json.txt");
file.open(QFile::WriteOnly);
file.write(QJsonDocument(arr).toJson());
}
This all works fine and produces the json file...it looks like this (first few lines):
[
{
"Address": 0,
"Bank": 0,
"DefaultValue": 0,
"Name": "V_ADC_IN",
"SpecialAction": 0,
"Type": 3
},
{
"Address": 1,
"Bank": 0,
"DefaultValue": 0,
"Name": "V_ADC_SCALE",
"SpecialAction": 0,
"Type": 3
},
{
"Address": 2,
"Bank": 0,
Now, I need to do the reverse...but my json object size is always 0! what is the problem?
QFile file(url);
file.open(QIODevice::ReadOnly | QIODevice::Text);
QString raw = file.readAll();
file.close();
QJsonDocument doc = QJsonDocument::fromJson(raw.toUtf8());
QJsonObject obj = doc.object();
QJsonArray arr = obj[""].toArray();
Your objects does not have an identifier...so you need to access by position in the array. Something like this:
QJsonDocument doc = QJsonDocument::fromJson(raw.toUtf8());
QJsonArray arr = doc.array(); // get array representation of the doc
for(int i = 0; i < arr.size(); i++) {
QJsonValue val = arr.at(i);
// The following line should thoritically prin the Name field
qDebug() << val.toObject().value("Name");
}

Receiving fatal error assigning QSharedPointer in QtTest

In TestGroup_Person, when I retrieve a QSharedPointer<-JB_TableRowProt> from JB_PersonDao and assign it to QSharedPointer<-JB_TableRowProt> aGroup_Person (in .h), I then get this error in the methods of TestGroup_Person.
Alternatively, if I retrieve a QSharedPointer<-JB_TableRowProt> from JB_DaoProt in each method (and don't assign it to QSharedPointer<-JB_TableRowProt> aGroup_Person), it works fine.
Can someone explain to me why this assignment appears to be causing the error please?
I got this error:
QFATAL : TestGroup_Person::test_getDBTable_Name() Received signal 11
Function time: 0ms Total time: 0ms
FAIL! : TestGroup_Person::test_getDBTable_Name() Received a fatal error.
Here's the code:
main:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStringList arguments = QCoreApplication::arguments();
QFile aFile(DATABASE_FILENAME); // remove existing SP3.db
if (aFile.exists())
aFile.remove();
map<QString, unique_ptr<QObject>> tests;
tests.emplace("group_person", make_unique<TestGroup_Person>());
if (arguments.size() >= 3 && arguments[1] == "-select") {
QString testName = arguments[2];
auto iter = tests.begin();
while(iter != tests.end()) {
if (iter->first != testName) {
iter = tests.erase(iter);
} else {
++iter;
}
}
arguments.removeOne("-select");
arguments.removeOne(testName);
}
int status = 0;
for(auto& test : tests) {
status |= QTest::qExec(test.second.get(), arguments);
}
return status;
}
TestGroup_Person.h
#include <QString>
#include <QtTest>
#include <QSharedPointer>
#include "A_DB_Classes/JB_DatabaseManager.h"
#include "A_Tables/JB_Group_Person.h"
class TestGroup_Person : public QObject
{
Q_OBJECT
public:
TestGroup_Person();
private Q_SLOTS:
void test_allFieldsEqualsFieldNames();
void test_getDBTable_FieldNames();
void test_getDBTable_Name();
void test_hasJoinTable();
void test_setValueForField();
void test_setStorageValueForField();
void test_getStorageFields();
private:
JB_DatabaseManager& mDB;
QSharedPointer<JB_TableRowProt> aGroup_Person;
};
TestGroup_Person.cpp:
TestGroup_Person::TestGroup_Person():
mDB(JB_DatabaseManager::instance())
{
aGroup_Person = mDB.aPersonDao.getJoinTableObject();
}
void TestGroup_Person::test_allFieldsEqualsFieldNames()
{
const QVector<QString>& aVector = aGroup_Person->getDBTable_FieldNames();
const QList<QString> aList = aGroup_Person->getAllFieldNames();
bool isThere = true;
QString fieldName = "";
QString aResult = "This field name does not exist in all_FieldNamesAndValuesH";
for (int i = 0; i < aVector.size() && isThere; ++i) {
fieldName = aVector.at(i);
isThere = aList.contains(aVector.at(i));
}
if (isThere)
aResult = fieldName;
QCOMPARE(fieldName, QString(aResult));
}
void TestGroup_Person::test_getDBTable_FieldNames()
{
const QVector<QString>& aVector = aGroup_Person->getDBTable_FieldNames();
QString fieldName = "";
for (int i = 0; i < aVector.size(); ++i) {
fieldName = fieldName + aVector.at(i) +",";
}
QVector<QString> fieldNames;
QVector<QString> columnHeadings;
aGroup_Person->getViewableFieldNamesAndHeadings(fieldNames, columnHeadings);
bool correct = fieldNames.count() == columnHeadings.count();
if (!correct)
correct = columnHeadings.count() == 0;
QCOMPARE(correct, true);
QCOMPARE(fieldName, QString("groupID,personID,jobID,grp_per_dateTimeStamp,"));
}
void TestGroup_Person::test_getDBTable_Name()
{
QCOMPARE(aGroup_Person->getDBTable_Name(), QString("Group_Person"));
}
Relevant method of JB_DaoProt:
QSharedPointer<JB_TableRowProt> JB_DaoProt::getJoinTableObject()
{
JB_TableRowProt* aJoinTable = new_JoinTableRowProt();
QSharedPointer<JB_TableRowProt> pJoinTable(aJoinTable);
return pJoinTable;
}

Error when try to read from a QFile

I want to read some data from a file with QT and then show data in a QTableWidget through a QComboBox.
void DemoDataView::on_comboBox_activated(const QString &arg1)
{
ui->tableWidget->setColumnCount(5);
ui->tableWidget->setRowCount(21);
ui->tableWidget->verticalHeader()->setVisible(false);
ui->tableWidget->setHorizontalHeaderLabels(QString("Age Range ; Male Population ; Male Percentage ; Female Population ; Female Percentage").split(";"));
ui->tableWidget->resizeColumnsToContents();
ui->tableWidget->resizeRowsToContents();
QFile inputFile("./data.txt");
if(!inputFile.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "Error", inputFile.errorString());
}
QTextStream in(&inputFile);
int rows = 0;
while(!in.atEnd()) {
QString mLine = in.readLine();
QStringList fields = mLine.split(" ");
QStringList::iterator it = fields.begin();
QString regName = *it;
ui->label->setText(arg1);
if(regName != "<END>" && QString::compare(regName, arg1) == 0) {
ui->label->setText(regName);
it++;
QString ageRange = *it;
it++;
QString nMale = *it;
double male = nMale.toDouble();
it++;
QString nFemale = *it;
double female = nFemale.toDouble();
ui->tableWidget->setItem(rows, 0, new QTableWidgetItem(ageRange));
ui->tableWidget->setItem(rows, 1, new QTableWidgetItem(nMale));
ui->tableWidget->setItem(rows, 3, new QTableWidgetItem(nFemale));
ui->tableWidget->setItem(rows, 2, new QTableWidgetItem(malePercCalc(male, female)));
ui->tableWidget->setItem(rows, 4, new QTableWidgetItem(femalePercCalc(male, female)));
rows++;
}
inputFile.close();
}
}
The file is in both the project folder and the build project folder.
When I run the application everything works good but in the Application Output tab I have this error message:
"QIODevice:: read (QFile, "./data.txt"): device not open"
Every time I click on a QComboBox item.
If it can be useful, this is the filling code of the QComboBox:
void DemoDataView::setComboBoxRegion() {
QFile inputFile("./data.txt");
if(!inputFile.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "Error", inputFile.errorString());
}
QTextStream in(&inputFile);
while(!in.atEnd()) {
QString mLine = in.readLine();
QStringList fields = mLine.split(" ");
QStringList::iterator it = fields.begin();
QString regName = *it;
if(regName != "<END>") {
if(ui->comboBox->findText(regName) == -1){
ui->comboBox->addItem(regName);
}
}
}
inputFile.close();
}
Your problem is that you are calling:
inputFile.close();
INSIDE of your loop, which means it is closed in the first loop. I can't really think of any cases that this would be the desired thing to happen;
To solve this, you should move it to the outside of the loop.

QT: How to replace number (Start, End) in a JSON from server

This is how my JSON file looks like. As you can see, the start_x, start_y, and end_x, end_y, degree_of_rotation is a number.
{
"ID" : "ROLL1",
"action" : "start",
"zone" :
{
"start_x" : 0,
"start_y" : 4,
"end_x" : 10,
"end_y" : 5,
"motion" :
{
"motion_type": "xxxxxx",
"degree_of_rotation": 30,
"rotation_direction": "yyyyyy",
"linear_direction": "+ve"
}
}
}
How can I replace and save the number in JSON from the server? Currently, this is what I have. Qt5 has a new JSON parser and I want to use it. The problem is that it isn't too clear about what the functions do
void JsonFileread::Json_File_Function()
{
try
{
qDebug() <<"file reading";
file.setFileName("/home/JSON/jsonfile.js");
file.open(QIODevice::ReadOnly | QIODevice::Text);
QFileDevice::FileError err = QFileDevice::NoError;
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() <<"Could not open file : "<<file.fileName() <<"for reading :"<<file.errorString()<<endl;
errMsg =file.errorString();
err =file.error();
cout<<"err : "<<err<<endl;
}
settings = file.readAll();
if (file.error() != QFile::NoError) {
qDebug() << QString("Failed to read from file %1, error: %2").arg(file.fileName()).arg(file.errorString());
}
if (settings.isEmpty()) {
qDebug() << "No data was currently available for reading from file" << file.fileName();
}
file.close();
object = EchoClient::jsonstringflag;
QJsonDocument sd = QJsonDocument::fromJson(settings.toUtf8());
QJsonObject sett2 = sd.object();
QJsonValue mainid = sett2["ID"];
mainid = mainid.toString();
QJsonValue action = sett2["action"];
actionstring = action.toString();
QJsonValue value = sett2.value(QString("zone"));
QJsonObject item = value.toObject();
QJsonValue startx = item["start_x"];
startvaluex = startx.toInt();
QJsonValue starty = item["start_y"];
startvaluey = starty.toInt();
QJsonValue endx = item["end_x"];
endvaluex = endx.toInt();
xendvaluestring = endx.toString();
qWarning() << endvaluex<<endl;
QJsonValue endy = item["end_y"];
endvaluey = endy.toInt();
yendvaluestring = endy.toString();
qWarning() << endvaluey<<endl;
QJsonValue motion = item.value(QString("motion"));
QJsonObject motion_object = motion.toObject();
QJsonValue motiontype = motion_object["motion_type"];
motiontypestring = motiontype.toString();
QJsonValue directionlinear = motion_object["linear_direction"];
lineardirection = directionlinear.toString();
QJsonValue rotatingangle = motion_object["degree_of_rotation"];
angleofrotation = rotatingangle.toInt();
}
catch (QJsonParseError error)
{
qDebug() << error.errorString();
}
catch(...)
{
qDebug() << "due to some other error";
}
}
So help to solve the problem
You can write to a QJsonObject very similar to how you read its properties
QJsonObject obj;
obj["key"] = value;
Once you have built the QJsonObject tree, set the top level element on a QJsonDocument and use it to generate the JSON content.

Custom class to XML using QSettings

I'd like to save custom class to XML using QSettings. But I always get XML without structure members.
#include <QCoreApplication>
#include <QtCore/qdatastream.h>
#include <qxmlstream.h>
#include <qdebug.h>
#include <QtCore/QSettings>
#include <QMetaType>
struct Interface_struct
{
QString name;
QString ip;
};
Q_DECLARE_METATYPE(Interface_struct)
QDataStream& operator <<(QDataStream& out, const Interface_struct& s)
{
out << s.name << s.ip;
return out;
}
QDataStream& operator >>(QDataStream& in, Interface_struct& s)
{
in >> s.name;
in >> s.ip;
return in;
}
static bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map)
{
qDebug()<< "read";
QXmlStreamReader reader(&device);
QString key;
while(!reader.atEnd())
{
reader.readNext();
if( reader.isStartElement() && reader.tokenString() != "Settings")
{
if( reader.text().isNull() )
{
// key = Settings
if(key.isEmpty())
{
key = reader.tokenString();
}
// key = Settings/Intervall
else
{
key += "/" + reader.tokenString();
}
}
else
{
map.insert(key, reader.text().data());
}
}
}
return true;
}
static bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map)
{
qDebug()<< "write";
QXmlStreamWriter writer(&device);
writer.writeStartDocument("1.0");
writer.writeStartElement("Settings");
foreach(QString key, map.keys())
{
foreach(QString elementKey, key.split("/"))
{
writer.writeStartElement(elementKey);
}
writer.writeCharacters(map.value(key).toString());
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndDocument();
return true;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qRegisterMetaType<Interface_struct>("Interface_struct");
qRegisterMetaTypeStreamOperators<Interface_struct>("Interface_struct");
{
Interface_struct s;
s.name = QString("br03000");
s.ip = QString("172.16.222.5");
const QSettings::Format xml_format =
QSettings::registerFormat("xml", readXmlFile, writeXmlFile);
if(xml_format == QSettings::InvalidFormat)
{
qDebug() << "InvalidFormat!";
return 0;
}
QSettings::setPath(xml_format, QSettings::UserScope, "/home/farit/test/");
QSettings settings(xml_format, QSettings::UserScope, "xml_cfg");
settings.setValue("network", QVariant::fromValue(s));
}
{
QSettings::Format xml_format =
QSettings::registerFormat("xml", readXmlFile, writeXmlFile);
QSettings::setPath(xml_format, QSettings::UserScope, "/home/farit/test/");
QSettings settings(xml_format, QSettings::UserScope, "xml_cfg");
QVariant value = settings.value("network");
Interface_struct interface = value.value<Interface_struct>();
qDebug() << "TEST: " << interface.name << interface.ip;
}
return 0;
}
I get this output:
read
write
read
TEST: "" ""
Press <RETURN> to close this window...
And XML looks like this:
<?xml version="1.0" encoding="UTF-8"?><Settings><network></network></Settings>
How can I save structure members of custom class to XML using QSettings?
UPDATE: I'm sorry, I forgot to mention, that is supposed to be done in Qt4.