Evgenii Legotckoi
Evgenii LegotckoiOct. 26, 2018, 5:35 p.m.

Qt/C++ - Tutorial 085. Work with QJsonObject, QJsonArray, QJsonDocument. Save and load JSON from files

Consider a small example of the formation of a JSON document from, for example, the text and the title of this text.

For example, the text has:

  • Title - First Title
  • Content - First Content

And so on

We will add this text to QJsonObject, which we will add to the QJsonArray text array. The array of objects will be in the general working QJsonObject, which we will save to a file.

We will do all this through a graphical interface in which we have:

  • QLineEdit - titleLineEdit - contains the title of the text to add
  • QTextEdit - contentTextEdit - contains the contents of the text to add
  • QTextEdit - jsonDocumentTextEdit - JSON document preview
  • QPushButton - addButton - button to add new text in JSON
  • QPushButton - clearButton - button to remove all texts from the current QJsonObject
  • QPushButton - saveButton - button to save JSON document to file
  • QPushButton - loadButton - button to read JSON from file

In this case, we will be able to read the JSON file and add additional texts to the read file.

The application will look like this.


Implementation

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QJsonObject>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    // Slot of adding new text to the array of texts
    void onAddButtonClicked();
    // Слот удаления всей информации о текстах в текущем объекте
    void onClearButtonClicked();
    // Slot save text in json file
    void onSaveButtonClicked();
    // Slot of loading texts into the program from json file
    void onLoadButtonClicked();

    Ui::Widget *ui;

    // The current json object you are working with
    QJsonObject m_currentJsonObject;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QFileDialog>
#include <QFile>
#include <QDir>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    // Connecting handler slots to button click signals
    connect(ui->addButton, &QPushButton::clicked, this, &Widget::onAddButtonClicked);
    connect(ui->clearButton, &QPushButton::clicked, this, &Widget::onClearButtonClicked);
    connect(ui->saveButton, &QPushButton::clicked, this, &Widget::onSaveButtonClicked);
    connect(ui->loadButton, &QPushButton::clicked, this, &Widget::onLoadButtonClicked);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::onAddButtonClicked()
{
    // Create a text object
    QJsonObject textObject;
    textObject["title"] = ui->titleLineEdit->text();                // Set the text header
    textObject["content"] = ui->contentTextEdit->toPlainText();     // Set the content of the text
    QJsonArray textsArray = m_currentJsonObject["texts"].toArray(); // We take the current array of texts, even if it does not exist, it will be created automatically
    textsArray.append(textObject);                                  // Add a text object to the array
    m_currentJsonObject["texts"] = textsArray;                      // Save the array back to the current object.

    // Set the text of the entire Json object in the text field for verification
    ui->jsonDocumentTextEdit->setText(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
}

void Widget::onClearButtonClicked()
{
    m_currentJsonObject = QJsonObject();    // Re-create the new current QJsonObject
    ui->jsonDocumentTextEdit->clear();      // Clear the text field
    // Set the text of the entire Json object in the text field to see that it is an empty object.
    // See the following -> {}
    ui->jsonDocumentTextEdit->setText(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
}

void Widget::onSaveButtonClicked()
{
    // Using the dialog box we get the file name with the absolute path.
    QString saveFileName = QFileDialog::getSaveFileName(this,
                                                        tr("Save Json File"),
                                                        QString(),
                                                        tr("JSON (*.json)"));
    QFileInfo fileInfo(saveFileName);   // Using QFileInfo
    QDir::setCurrent(fileInfo.path());  // set the current working directory where the file will be, otherwise it may not work
    // Create a file object and open it for writing.
    QFile jsonFile(saveFileName);
    if (!jsonFile.open(QIODevice::WriteOnly))
    {
        return;
    }

    // Write the current Json object to a file.
    jsonFile.write(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
    jsonFile.close();   // Close file
}

void Widget::onLoadButtonClicked()
{
    // Choose a file
    QString openFileName = QFileDialog::getOpenFileName(this,
                                                        tr("Open Json File"),
                                                        QString(),
                                                        tr("JSON (*.json)"));
    QFileInfo fileInfo(openFileName);   // Using QFileInfo
    QDir::setCurrent(fileInfo.path());  // set the current working directory where the file will be
    // Create a file object and open it for reading.
    QFile jsonFile(openFileName);
    if (!jsonFile.open(QIODevice::ReadOnly))
    {
        return;
    }

    // Read the entire file
    QByteArray saveData = jsonFile.readAll();
    // Create QJsonDocument
    QJsonDocument jsonDocument(QJsonDocument::fromJson(saveData));
    // From which we select an object into the current working QJsonObject
    m_currentJsonObject = jsonDocument.object();
    // Clear the text field
    ui->jsonDocumentTextEdit->clear();
    // And set the contents of the Json object in the verification text field.
    ui->jsonDocumentTextEdit->setText(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
}

Conclusion

In this particular case, QFileDialog is used to get the path to the recordable file and the file being opened. Of course, from manipulating an existing file, only adding new texts is available and you can open any correct JSON document and then add text to it. But for example, I believe that more is not needed.

Example on GitHub repository of EVILEG

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Михаиллл
  • Oct. 28, 2018, 11:41 a.m.

Скажите пожалуйста, в 55 строке получаем saveFileNam, это видимо полное имя файла. Но где потом сообщается полный путь  файлу json при его записи?

Evgenii Legotckoi
  • Oct. 28, 2018, 11:50 a.m.

В saveFileName будет полный путь к файлу с его именем. В диалоге просто вводите имя файла с расширением, а QFileDialog возвращает имя файла и полный путь к нему.

Можете увидеть это, если добавите вывод в qDebug

qDebug() << saveFileName;

А через fileInfo я выдернул путь к файлу, чтобы установить рабочую директорию через QDir::setCurrent();, чтобы указать, где именно сохраняется файл. А когда я передаю saveFileName в QFile, даже с наличием пути в имени, всё будет нормально работать, путь должен быть отброшен автоматически.


Михаиллл
  • Oct. 29, 2018, 2:12 a.m.

Спасибо.

Скажите пожалуйста, зачем 65 строка? написал по образцу  часть кода, выдало ошибку D:\QTProject\ReaderResume\main.cpp:58: ошибка: return-statement with no value, in function returning 'int' [-fpermissive]

return;

^

Без return работает


Evgenii Legotckoi
  • Oct. 29, 2018, 4:08 a.m.

зачем вы слот написали с возвращаемым значением int?

У вас сигнатура в вашем коде так написана

int someFunc();

слоту обычно не требуется возвращаемое значение.

return прерывает выполнение метода, чтобы не шло дальше, если файл не открылся в данном случае.


Михаиллл
  • Oct. 29, 2018, 4:26 a.m.

Спасибо

Скажите пожалуйста, как добавить в массив QJsonArray другой массив QVector<QString> TextArra?

Как я понял, это можно сделать в цикле поочередно для каждого члена массива, но можно ли сразу перевести одной командой?



Evgenii Legotckoi
  • Oct. 29, 2018, 4:40 a.m.

Думаю, что через алгоритмические методы вставки из стандартной библиотеки и использование итераторов с лямбда функциями можно написать и в одну строку.

Но судя по вашим вопросам, могу сказать, что вы не знакомы со всем этим зоопарком, поэтому пока не забивайте себе этим голову, в процессе работы сами прийдёте к использованию данного функционала. Так что сделайте через цикл поочерёдно. Просто напишите

QJsonArray textsArray;
for (const QString& str : TextArray)
{
        textsArray.push_back(str);
}



Также вы можете сами написать эту вспомогательную команду.

Михаиллл
  • Oct. 29, 2018, 11:07 a.m.

Спасибо. И скажите пожалуйста, как перевести QString в QJsonValue


Evgenii Legotckoi
  • Oct. 29, 2018, 11:18 a.m.

QJsonValue::fromVariant(const QVariant& variant);

Михаиллл
  • Oct. 29, 2018, 12:02 p.m.

Спасибо.

Скажите пожалуйста, в json файле размещен массив, в этот массив нужно добавить еще один элемент массива. Но считывать весь массив - тратить дополнительное время. Можно ли, при условии, что я знаю, что там только один массив, как то быстро добавить один элемент?


Evgenii Legotckoi
  • Oct. 29, 2018, 3:22 p.m.

Возможно, через итератор можно будет сделать. Я не проверял. сам по себе метод toArray() возвращает копию массива...

На первый взгляд я не увидел необходимой возможности, хотя подумал об этом.

Возможно с итераторами через метод find, можно будет взять массив и уже в нём покопаться. Но не факт.


Михаиллл
  • Oct. 31, 2018, 4:50 a.m.

А можно сразу перейти в конец документа, если нет ], то записывать с начала, а если есть ] , то ставить запятую и дописывать еще один элемент?

Evgenii Legotckoi
  • Oct. 31, 2018, 4:52 a.m.

Это уже вручную нужно реализовывать. Только это не нужно, пока действительно не будет проблемы по производительности.

А вообще, если нужно хранение данных, то возможно и насчёт базы данных стоит подумать. Хотя бы SQLite можно использовать. Это будет эффективнее.


Юрий
  • June 30, 2020, 5:34 p.m.

Как отредактировать данные?

{
    "connect": [
        {
            "id": 1,
            "name": "Data1",
        },
        {
            "id": 2,
            "name": "Data2",
        }
    ]
}

Михаиллл
  • July 1, 2020, 2:54 a.m.

Смотря что хотите и в каком виде эти данные. Если в текстовом, то их нужно прочитать, перевести в QJsonDocument, из него достать массив connect, и уже обращаясь у элементам массива, получвя из него объекты редактировать их

Comments

Only authorized users can post comments.
Please, Log in or Sign up
m

C++ - Тест 003. Условия и циклы

  • Result:85points,
  • Rating points6
в

C++ - Тест 003. Условия и циклы

  • Result:50points,
  • Rating points-4
l

C++ - Test 005. Structures and Classes

  • Result:91points,
  • Rating points8
Last comments
k
kmssrFeb. 9, 2024, 5:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 9:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 7:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 8:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
AC
Alexandru CodreanuJan. 19, 2024, 10:57 p.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 7:57 p.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 3:18 p.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 5:48 p.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks