Евгений Легоцкой26 октября 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 файл и добавить дополнительные тексты в считанный файл.

Приложение будет выглядеть так.

Реализация

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:
    // Слот добавления нового текста в массив текстов
    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 хостинг.
Поддержать автора Donate

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

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

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

qDebug() << saveFileName;

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


Спасибо.

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

return;

^

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


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

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

int someFunc();

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

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


Спасибо

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

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



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

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

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



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

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


QJsonValue::fromVariant(const QVariant& variant);

Спасибо.

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


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

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

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


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

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

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


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

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

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
Timeweb

Позвольте мне порекомендовать вам отличный хостинг, на котором расположен EVILEG.

В течение многих лет Timeweb доказывает свою стабильность.

Для проектов на Django рекомендую VDS хостинг

Посмотреть Хостинг
J

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

  • Результат:93баллов,
  • Очки рейтинга8
V
  • Vitreg
  • 26 октября 2020 г. 2:35

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

  • Результат:73баллов,
  • Очки рейтинга1
V
  • Vitreg
  • 26 октября 2020 г. 2:23

C++ - Тест 005. Структуры и Классы

  • Результат:83баллов,
  • Очки рейтинга4
Последние комментарии

Qt/C++ - Урок 074. Генерация псевдослучайных чисел с использованием случайной библиотеки STD

А использование функции global() не решает ли эти проблемы? value = QRandomGenerator::global()->bounded(15, 43); Получаемая последовательность каждый раз новая.

Qt/C++ - Урок 074. Генерация псевдослучайных чисел с использованием случайной библиотеки STD

А использование функции global() не решает ли эти проблемы? value = QRandomGenerator::global()->bounded(15, 43); Получаемая последовательность каждый раз новая.
S

QML - Урок 026. Intents с Qt для Android, часть 1

Есть ли возможность приведения java типа у QAndroidJniObject? Интересует конкретно class to
ВК

Qt/C++ - Урок 015. QTableWidget или Как сделать таблицу с чекбоксами

Кто-нибудь знает, как сделать так, чтобы в QTableWidget состоящей из чекбоксов в строке таблицы можно было выбрать только один checkbox ?

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

QSqlTableModel выполняет ряд стандартных операций для одной таблицы из базы данных. Поэтому там и реализован функционал по удалению и редактированию. QSqlQueryModel позволяет выполнить запр…
Сейчас обсуждают на форуме
D

LibreOffice QT Widget

Я бы хотел интегрировать приложения из LibreOffice в свою программу. В идеале использовать их как виджеты Наткнулся на пакет libreoffice-qt5, который вроде как позволяет это делать htt…

Создание черновика как на авито и тд

А черновик в свою очередь нужен пока только для получения id, который нужен для мультизагружки изображений и привязки их к посту. как то так... я бы вообще решал это так: class P…
  • Nomad
  • 1 октября 2020 г. 5:22

MyForm(forms.Form): - непонятка

понятно спасибо
S

QWebView android

На android не запускается, иначе я бы не создавал этот пост. Собственно, вопрос я решил сам, там ещё понадобилось setDomStorageEnabled(true) вызвать.

не могу передать стринг с QLineEdit

QLineEdit *myLineEdit = new QLineEdit("line edit name", this); QString str = myLineEdit->text();
О нас
Услуги
© EVILEG 2015-2020
Рекомендует хостинг TIMEWEB