Evgenii Legotckoi
Evgenii Legotckoi26. Oktober 2018 17:35

Qt/C++ - Tutorial 085. Arbeiten Sie mit QJsonObject, QJsonArray, QJsonDocument. JSON aus Dateien speichern und laden

Betrachten wir ein kleines Beispiel für die Generierung eines JSON-Dokuments beispielsweise aus Text und dem Titel dieses Textes.

Der Text hat zum Beispiel:

  • Titel - Erster Titel
  • Inhalt - Erster Inhalt

Usw.

Wir fügen diesen Text zu QJsonObject hinzu, das wir dem Array von Texten QJsonArray hinzufügen werden. Das Array von Objekten befindet sich im gemeinsamen Arbeitsverzeichnis QJsonObject , das wir in einer Datei speichern.

Wir werden dies alles über eine grafische Oberfläche tun, die Folgendes hat:

  • QLineEdit - titleLineEdit - enthält den Titel des hinzuzufügenden Textes
  • QTextEdit - contentTextEdit - enthält den Inhalt des hinzuzufügenden Textes
  • QTextEdit - jsonDocumentTextEdit - JSON-Dokumentvorschau
  • QPushButton - addButton - Schaltfläche zum Hinzufügen von neuem Text zu JSON
  • QPushButton - clearButton - Schaltfläche zum Entfernen aller Texte aus dem aktuellen QJsonObject
  • QPushButton - saveButton - Schaltfläche zum Speichern des JSON-Dokuments in einer Datei
  • QPushButton - loadButton - Schaltfläche zum Lesen von JSON aus einer Datei

In diesem Fall können wir die JSON-Datei lesen und der gelesenen Datei zusätzliche Texte hinzufügen.

Die Anwendung wird wie folgt aussehen.


Implementierung

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));
}

Fazit

In diesem speziellen Fall wird QFileDialog verwendet, um den Pfad zu der Datei zu erhalten, die geschrieben wird, und die Datei, die geöffnet wird. Natürlich ist von den Manipulationen mit einer bereits vorhandenen Datei nur das Hinzufügen neuer Texte verfügbar, und Sie können jedes gültige JSON-Dokument öffnen und ihm dann Text hinzufügen. Aber zum Beispiel glaube ich, dass mehr nicht nötig ist.

Beispiel für GitHub-Repositories EVILEG

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Михаиллл
  • 28. Oktober 2018 11:41

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

Evgenii Legotckoi
  • 28. Oktober 2018 11:50

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

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

qDebug() << saveFileName;

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


Михаиллл
  • 29. Oktober 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. Oktober 2018 04:08

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

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

int someFunc();

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

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


Михаиллл
  • 29. Oktober 2018 04:26

Спасибо

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

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



Evgenii Legotckoi
  • 29. Oktober 2018 04:40

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

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

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



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

Михаиллл
  • 29. Oktober 2018 11:07

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


Evgenii Legotckoi
  • 29. Oktober 2018 11:18

QJsonValue::fromVariant(const QVariant& variant);

Михаиллл
  • 29. Oktober 2018 12:02

Спасибо.

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


Evgenii Legotckoi
  • 29. Oktober 2018 15:22

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

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

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


Михаиллл
  • 31. Oktober 2018 04:50

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

Evgenii Legotckoi
  • 31. Oktober 2018 04:52

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

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


Юрий
  • 30. Juni 2020 17:34

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

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

Михаиллл
  • 1. Juli 2020 02:54

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

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
A
ALO1ZE19. Oktober 2024 08:19
Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken