Evgenii Legotckoi
Evgenii Legotckoi26 жовтня 2018 р. 17:35

Qt/C++ - Підручник 085. Робота з QJsonObject, QJsonArray, QJsonDocument. Збережіть і завантажте JSON з файлів

Розглянемо невеликий приклад формування JSON документа з, наприклад, тексту і заголовка цього тексту.

Наприклад текст має:

  • Заголовок - First Title
  • Контент - First Content

І т.д.

Додаватимемо цей текст у QJsonObject , який будемо додавати в масив текстів QJsonArray . Масив об'єктів перебуватиме у загальному робочому QJsonObject , який зберігатимемо у файл.

Все це робитимемо через графічний інтерфейс, в якому є:

  • QLineEdit - titleLineEdit - містить заголовок тексту, який потрібно додати
  • QTextEdit - contentTextEdit - містить вміст тексту, який потрібно додати
  • QTextEdit - jsonDocumentTextEdit - перегляд JSON документа
  • QPushButton - addButton - кнопка для додавання нового тексту в JSON
  • QPushButton - clearButton - кнопка для видалення всіх текстів з поточного QJsonObject
  • QPushButton - saveButton - кнопка для збереження JSON документа у файл
  • QPushButton - loadButton - кнопка для зчитування JSON з файлу

В даному випадку зможемо рахувати JSON файл та додати додаткові тексти до ліченого файлу.

Програма виглядатиме так.


Реалізація

віджет.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:
    // Слот добавления нового текста в массив текстов
    void onAddButtonClicked();
    // Слот удаления всей информации о текстах в текущем объекте
    void onClearButtonClicked();
    // Слот сохранения текстов в json файл
    void onSaveButtonClicked();
    // Слот загрузки текстов в программу из json файла
    void onLoadButtonClicked();

    Ui::Widget *ui;

    // Текущий json объект, с которым производится работа
    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);

    // Подключение слотов обработчиков к сигналам клика по кнопкам
    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()
{
    // Создаём объект текста
    QJsonObject textObject;
    textObject["title"] = ui->titleLineEdit->text();                // Устанавливаем заголовок текста
    textObject["content"] = ui->contentTextEdit->toPlainText();     // Устанавливаем содержание текста
    QJsonArray textsArray = m_currentJsonObject["texts"].toArray(); // Забираем текущий массив текстов, даже если он не существует, он будет создан автоматически
    textsArray.append(textObject);                                  // Добавляем объект текста в массив
    m_currentJsonObject["texts"] = textsArray;                      // Сохраняем массив обратно в текущий объект

    // Устанавливаем текст всего Json объекта в текстовое поле для проверки
    ui->jsonDocumentTextEdit->setText(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
}

void Widget::onClearButtonClicked()
{
    m_currentJsonObject = QJsonObject();    // Пересоздаём новый текущий QJsonObject
    ui->jsonDocumentTextEdit->clear();      // Очищаем текстовое поле
    // Устанавливаем текст всего Json объекта в текстовое поле, чтобы увидеть, что это пустой объект.
    // Увидите следующее -> {}
    ui->jsonDocumentTextEdit->setText(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
}

void Widget::onSaveButtonClicked()
{
    // С помощью диалогового окна получаем имя файла с абсолютным путём
    QString saveFileName = QFileDialog::getSaveFileName(this,
                                                        tr("Save Json File"),
                                                        QString(),
                                                        tr("JSON (*.json)"));
    QFileInfo fileInfo(saveFileName);   // С помощью QFileInfo
    QDir::setCurrent(fileInfo.path());  // установим текущую рабочую директорию, где будет файл, иначе может не заработать
    // Создаём объект файла и открываем его на запись
    QFile jsonFile(saveFileName);
    if (!jsonFile.open(QIODevice::WriteOnly))
    {
        return;
    }

    // Записываем текущий объект Json в файл
    jsonFile.write(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
    jsonFile.close();   // Закрываем файл
}

void Widget::onLoadButtonClicked()
{
    // Выбираем файл
    QString openFileName = QFileDialog::getOpenFileName(this,
                                                        tr("Open Json File"),
                                                        QString(),
                                                        tr("JSON (*.json)"));
    QFileInfo fileInfo(openFileName);   // С помощью QFileInfo
    QDir::setCurrent(fileInfo.path());  // установим текущую рабочую директорию, где будет файл
    // Создаём объект файла и открываем его на чтение
    QFile jsonFile(openFileName);
    if (!jsonFile.open(QIODevice::ReadOnly))
    {
        return;
    }

    // Считываем весь файл
    QByteArray saveData = jsonFile.readAll();
    // Создаём QJsonDocument
    QJsonDocument jsonDocument(QJsonDocument::fromJson(saveData));
    // Из которого выделяем объект в текущий рабочий QJsonObject
    m_currentJsonObject = jsonDocument.object();
    // Очищаем текстовое поле
    ui->jsonDocumentTextEdit->clear();
    // И устанавливаем в проверочное текстовое поле содержимое Json объекта
    ui->jsonDocumentTextEdit->setText(QJsonDocument(m_currentJsonObject).toJson(QJsonDocument::Indented));
}

Висновок

У даному конкретному випадку використовується QFileDialog, щоб отримати шлях до файлу, що записується, і відкривається файлу. Звичайно, з маніпуляцій з вже існуючим файлом доступне лише додавання нових текстів і можна відкрити будь-який коректний JSON документ, а потім додати до нього текст. Але для прикладу вважаю, що більше не потрібно.

Приклад сховищ GitHub EVILEG

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Михаиллл
  • 28 жовтня 2018 р. 11:41

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

Evgenii Legotckoi
  • 28 жовтня 2018 р. 11:50

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

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

qDebug() << saveFileName;

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


Михаиллл
  • 29 жовтня 2018 р. 02:12

Спасибо.

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

return;

^

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


Evgenii Legotckoi
  • 29 жовтня 2018 р. 04:08

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

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

int someFunc();

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

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


Михаиллл
  • 29 жовтня 2018 р. 04:26

Спасибо

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

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



Evgenii Legotckoi
  • 29 жовтня 2018 р. 04:40

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

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

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



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

Михаиллл
  • 29 жовтня 2018 р. 11:07

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


Evgenii Legotckoi
  • 29 жовтня 2018 р. 11:18

QJsonValue::fromVariant(const QVariant& variant);

Михаиллл
  • 29 жовтня 2018 р. 12:02

Спасибо.

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


Evgenii Legotckoi
  • 29 жовтня 2018 р. 15:22

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

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

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


Михаиллл
  • 31 жовтня 2018 р. 04:50

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

Evgenii Legotckoi
  • 31 жовтня 2018 р. 04:52

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

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


Юрий
  • 30 червня 2020 р. 17:34

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

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

Михаиллл
  • 01 липня 2020 р. 02:54

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

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
d
  • dsfs
  • 26 квітня 2024 р. 04:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
d
  • dsfs
  • 26 квітня 2024 р. 04:45

C++ - Тест 002. Константы

  • Результат:50бали,
  • Рейтинг балів-4
d
  • dsfs
  • 26 квітня 2024 р. 04:35

C++ - Тест 001. Первая программа и типы данных

  • Результат:73бали,
  • Рейтинг балів1
Останні коментарі
k
kmssr08 лютого 2024 р. 18:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 01:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 10:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 08:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 грудня 2023 р. 21:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
IscanderChe
IscanderChe30 квітня 2024 р. 04:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
G
Gar22 квітня 2024 р. 05:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 квітня 2024 р. 07:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 квітня 2024 р. 06:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 квітня 2024 р. 02:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь

Слідкуйте за нами в соціальних мережах