From fbd1be96d84525fd3e1e1fbf9391823f43d467f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B7=E5=BA=8A=E5=B0=B1=E7=8A=AF=E5=9B=B0?= <11730503+psx123456@user.noreply.gitee.com> Date: Thu, 16 Jan 2025 09:10:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8json=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JsonTreeItem.cpp | 163 ++++++++++++++++ JsonTreeItem.h | 63 +++++++ JsonTreeModel.cpp | 313 +++++++++++++++++++++++++++++++ JsonTreeModel.h | 63 +++++++ chargControlBox_cfgFile.pro | 4 + chargControlBox_cfgFile.pro.user | 2 +- mainwindow.cpp | 74 +++++++- mainwindow.h | 11 +- mainwindow.ui | 15 +- 9 files changed, 700 insertions(+), 8 deletions(-) create mode 100644 JsonTreeItem.cpp create mode 100644 JsonTreeItem.h create mode 100644 JsonTreeModel.cpp create mode 100644 JsonTreeModel.h diff --git a/JsonTreeItem.cpp b/JsonTreeItem.cpp new file mode 100644 index 0000000..48825d2 --- /dev/null +++ b/JsonTreeItem.cpp @@ -0,0 +1,163 @@ +#include "JsonTreeItem.h" + +JsonTreeItem::JsonTreeItem(JsonTreeItem *parent) + :theParentItem(parent) + ,theItemType(JsonTreeItem::None) + ,theItemDatas({{0,"[Key]"},{1,"[Value]"}}) //默认两行 +{ +} + +JsonTreeItem::JsonTreeItem(const QHash &datas, JsonTreeItem::JsonItemType type, JsonTreeItem *parent) + :theParentItem(parent) + ,theItemType(type) + ,theItemDatas(datas) +{ +} + +JsonTreeItem::~JsonTreeItem() +{ + deleteAllChild(); +} + +bool JsonTreeItem::insertChild(int row, JsonTreeItem *child) +{ + if(row<0||row>theChildItems.count()) + return false; + theChildItems.insert(row,child); + child->setParentItem(this); + return true; +} + +bool JsonTreeItem::removeChild(int row) +{ + if(row<0||row+1>theChildItems.count()) + return false; + delete theChildItems.takeAt(row); + return true; +} + +bool JsonTreeItem::insertChildren(int row, int count) +{ + if(row<0||row>theChildItems.count()) + return false; + for(int i=0;isetType(JsonTreeItem::Value); + //这里新增的次序无所谓row+i + theChildItems.insert(row,item); + } + return true; +} + +bool JsonTreeItem::removeChildren(int row, int count) +{ + if (row<0||row+count>theChildItems.count()) + return false; + for(int i=0;isetParentItem(this); +} + +void JsonTreeItem::deleteAllChild() +{ + qDeleteAll(theChildItems); + theChildItems.clear(); +} + +JsonTreeItem *JsonTreeItem::childItem(int row) +{ + return theChildItems.value(row); +} + +JsonTreeItem *JsonTreeItem::parentItem() +{ + return theParentItem; +} + +void JsonTreeItem::setParentItem(JsonTreeItem *parent) +{ + theParentItem=parent; +} + +int JsonTreeItem::childCount() const +{ + return theChildItems.count(); +} + +int JsonTreeItem::columnCount() const +{ + return theItemDatas.count(); +} + +QVariant JsonTreeItem::data(int column) const +{ + return theItemDatas.value(column,QVariant()); +} + +void JsonTreeItem::setData(int column, const QVariant &val) +{ + theItemDatas.insert(column,val); +} + +int JsonTreeItem::row() const +{ + if(theParentItem) + return theParentItem->theChildItems.indexOf(const_cast(this)); + return 0; +} + +bool JsonTreeItem::editable(int column) const +{ + //在保留默认结构的情况下 + //root的key-value都不可编辑 + //-->parent:nullptr + //array下级的key不可编辑 + //-->parent:array + //array或object的value不可编辑 + //-->type() + //此外,如果希望key不可变,column==0返回false即可 + if((!theParentItem||!theParentItem->parentItem())|| + ((0==column)&&(theParentItem->type()==JsonTreeItem::Array))|| + ((1==column)&&((type()==JsonTreeItem::Array)||(type()==JsonTreeItem::Object)))) + return false; + return true; +} + +QString JsonTreeItem::key() const +{ + return theItemDatas.value(0,"").toString(); +} + +void JsonTreeItem::setKey(const QString &key) +{ + theItemDatas[0]=key; +} + +QVariant JsonTreeItem::value() const +{ + return theItemDatas.value(1,0); +} + +void JsonTreeItem::setValue(const QVariant &value) +{ + theItemDatas[1]=value; +} + +JsonTreeItem::JsonItemType JsonTreeItem::type() const +{ + return theItemType; +} + +void JsonTreeItem::setType(JsonTreeItem::JsonItemType type) +{ + theItemType=type; +} + diff --git a/JsonTreeItem.h b/JsonTreeItem.h new file mode 100644 index 0000000..c1cc7be --- /dev/null +++ b/JsonTreeItem.h @@ -0,0 +1,63 @@ +#ifndef JSONTREEITEM_H +#define JSONTREEITEM_H + +#include + +//对于多种结构,可以写一个item抽象父类 +//我这个Item比较简单,基本都是靠外部来设置 +class JsonTreeItem +{ +public: + //item的类型,None为无效的类型 + enum JsonItemType{ + None, + Object, + Array, + Value + }; +public: + explicit JsonTreeItem(JsonTreeItem *parent=nullptr); + explicit JsonTreeItem(const QHash &datas,JsonTreeItem::JsonItemType type,JsonTreeItem *parent=nullptr); + ~JsonTreeItem(); + + //增删操作 + bool insertChild(int row,JsonTreeItem *child); + bool removeChild(int row); + bool insertChildren(int row,int count); + bool removeChildren(int row,int count); + void appendChild(JsonTreeItem *child); + void deleteAllChild(); + + //用于Model结构 + JsonTreeItem *childItem(int row); + JsonTreeItem *parentItem(); + void setParentItem(JsonTreeItem *parent); + int childCount() const; + int columnCount() const; + QVariant data(int column) const; + void setData(int column,const QVariant &val); + int row() const; + bool editable(int column) const; + //QHash roleNames() const; + + //便于Json操作 + QString key() const; + void setKey(const QString &key); + QVariant value() const; + void setValue(const QVariant &value); + JsonTreeItem::JsonItemType type() const; + void setType(JsonTreeItem::JsonItemType type); + +private: + JsonTreeItem *theParentItem; //构造函数来初始化parent + QList theChildItems; //append来添加child + JsonItemType theItemType; + //hash内容 + //1:key + //2:value + //用hash是为了便于扩展,比如增加勾选列等 + //如果只是简单的key+value两行数据,就用QString+QVariant就行了 + QHash theItemDatas; //存放每列(角色)的内容(qml的tree使用角色) +}; + +#endif // JSONTREEITEM_H diff --git a/JsonTreeModel.cpp b/JsonTreeModel.cpp new file mode 100644 index 0000000..c6c166b --- /dev/null +++ b/JsonTreeModel.cpp @@ -0,0 +1,313 @@ +#include "JsonTreeModel.h" +#include + +#include +#include + +JsonTreeModel::JsonTreeModel(QObject *parent) + : QAbstractItemModel(parent),theRootItem(new JsonTreeItem(nullptr)) +{ + +} + +JsonTreeModel::~JsonTreeModel() +{ + delete theRootItem; +} + +bool JsonTreeModel::loadJson(const QString &filepath) +{ + //判断路径以及是否正常打开 + if(filepath.isEmpty()) + return false; + QFile file(filepath); + if(!file.open(QIODevice::ReadOnly|QIODevice::Text)) + return false; + + //读取数据后关闭文件 + const QByteArray raw_data=file.readAll(); + file.close(); + + //解析为Json文档 + QJsonParseError json_error; + QJsonDocument json_doc=QJsonDocument::fromJson(raw_data,&json_error); + + //是否正常解析Json数据 + if(json_doc.isNull()||json_doc.isEmpty()||json_error.error!=QJsonParseError::NoError) + return false; + + emit beginResetModel(); + theRootItem->deleteAllChild();//清空之前的model + + //判断是object{}还是array[]的Json + if(json_doc.isObject()){ + //解析文档中的Object + parseObject("[Root]",json_doc.object(),theRootItem); + }else if(json_doc.isArray()){ + //解析文档中的Array + parseArray("[Root]",json_doc.array(),theRootItem); + } + + emit endResetModel(); + + qDebug()<<"load json file"; + return true; +} + +bool JsonTreeModel::dumpJson(const QString &filepath) +{ + if(filepath.isEmpty()) + return false; + + //root 的child最多也只有一个 + if(!theRootItem||theRootItem->childCount()==0) + return false; + JsonTreeItem *top_level_item=theRootItem->childItem(0); + if(!top_level_item) + return false; + + //遍历Tree生成JsonDocument + QJsonDocument json_doc; + switch (top_level_item->type()) { + case JsonTreeItem::Object: + json_doc=QJsonDocument::fromVariant(dumpObject(top_level_item)); + break; + case JsonTreeItem::Array: + json_doc=QJsonDocument::fromVariant(dumpArray(top_level_item)); + break; + default: + break; + } + + //导出Json + QFile file(filepath); + if(!file.open(QIODevice::WriteOnly|QIODevice::Text)) + return false; + //转换为bytearray,Compact没有换行,Indented有换行可读性更强 + file.write(json_doc.toJson(QJsonDocument::Indented)); + file.close(); + + qDebug()<<"dump json file"; + return true; +} + +QModelIndex JsonTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + JsonTreeItem *parentItem=getItem(parent); + JsonTreeItem *childItem = parentItem->childItem(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex JsonTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + JsonTreeItem *childItem = getItem(index); + JsonTreeItem *parentItem = childItem->parentItem(); + + if (parentItem == theRootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +int JsonTreeModel::rowCount(const QModelIndex &parent) const +{ + JsonTreeItem *parentItem = getItem(parent); + return parentItem->childCount(); +} + +int JsonTreeModel::columnCount(const QModelIndex &parent) const +{ + JsonTreeItem *parentItem = getItem(parent); + return parentItem->columnCount(); +} + +QVariant JsonTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role != Qt::DisplayRole && role != Qt::EditRole) + return QVariant(); + + JsonTreeItem *item = getItem(index); + return item->data(index.column()); +} + +Qt::ItemFlags JsonTreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + JsonTreeItem *item = getItem(index); + return (item->editable(index.column())?Qt::ItemIsEditable:Qt::NoItemFlags) + |QAbstractItemModel::flags(index); +} + +bool JsonTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (role != Qt::EditRole) + return false; + + JsonTreeItem *item = getItem(index); + item->setData(index.column(), value); + emit dataChanged(index, index, {role}); + + return true; +} + +bool JsonTreeModel::insertRows(int row, int count, const QModelIndex &parent) +{ + JsonTreeItem *parentItem=getItem(parent); + + beginInsertRows(parent, row, row+count-1); + const bool result=parentItem->insertChildren(row,count); + endInsertRows(); + + return result; +} + +bool JsonTreeModel::removeRows(int row, int count, const QModelIndex &parent) +{ + JsonTreeItem *parentItem=getItem(parent); + + beginRemoveRows(parent, row, row+count-1); + const bool result=parentItem->removeChildren(row,count); + endRemoveRows(); + + return result; +} + +JsonTreeItem *JsonTreeModel::getItem(const QModelIndex &index) const +{ + if (index.isValid()) { + JsonTreeItem *item = static_cast(index.internalPointer()); + if (item) + return item; + } + return theRootItem; +} + +void JsonTreeModel::parseObject(const QString &key, const QJsonObject &obj, JsonTreeItem *&item) +{ + //构造Object节点 + JsonTreeItem *child=new JsonTreeItem({{0,key},{1,"[Object]"}},JsonTreeItem::Object,item); + item->appendChild(child); + + //遍历Object的keys + const QStringList keys=obj.keys(); + for(const QString &item_key:keys){ + //qDebug()<<"key:"<appendChild(child); + + //遍历Array + for(int i=0;iappendChild(child); +} + +QVariantMap JsonTreeModel::dumpObject(JsonTreeItem *&item) const +{ + QVariantMap json_obj; //QVariantMap对应QJsonObject + const int child_count=item->childCount(); + for(int i=0;ichildItem(i); + if(!child) continue; + //为什么不用一个返回QVariant的函数之类的封装下? + switch (child->type()) { + case JsonTreeItem::Object: + json_obj.insert(child->key(),dumpObject(child)); + break; + case JsonTreeItem::Array: + json_obj.insert(child->key(),dumpArray(child)); + break; + case JsonTreeItem::Value: + json_obj.insert(child->key(),dumpValue(child)); + break; + default: + break; + } + } + return json_obj; +} + +QVariantList JsonTreeModel::dumpArray(JsonTreeItem *&item) const +{ + QVariantList json_arr; //QVariantList对应QJsonArray + const int child_count=item->childCount(); + for(int i=0;ichildItem(i); + if(!child) continue; + switch (child->type()) { + case JsonTreeItem::Object: + json_arr.append(dumpObject(child)); + break; + case JsonTreeItem::Array: + json_arr.append(dumpArray(child)); + break; + case JsonTreeItem::Value: + json_arr.append(dumpValue(child)); + break; + default: + break; + } + } + return json_arr; +} + +QVariant JsonTreeModel::dumpValue(JsonTreeItem *&item) const +{ + //QVariant对应QJsonValue + return item->value(); +} + diff --git a/JsonTreeModel.h b/JsonTreeModel.h new file mode 100644 index 0000000..f623397 --- /dev/null +++ b/JsonTreeModel.h @@ -0,0 +1,63 @@ +#ifndef JSONTREEMODEL_H +#define JSONTREEMODEL_H + +#include + +#include +#include +#include +#include +#include +#include + +#include "JsonTreeItem.h" + +class JsonTreeModel : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit JsonTreeModel(QObject *parent = nullptr); + ~JsonTreeModel(); + + //导入导出数据 + bool loadJson(const QString &filepath); + bool dumpJson(const QString &filepath); + + //tree数据展示 + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + //支持编辑 + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole) override; + + bool insertRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + + //QHash roleNames() const override; //qml中需要,widget不用 + +private: + JsonTreeItem *getItem(const QModelIndex &index) const; + //解析并生成tree + void parseObject(const QString &key,const QJsonObject& obj,JsonTreeItem *&item); + void parseArray(const QString &key,const QJsonArray& arr,JsonTreeItem *&item); + void parseValue(const QString &key,const QJsonValue& val,JsonTreeItem *&item); + //生成json节点 + QVariantMap dumpObject(JsonTreeItem *&item) const; + QVariantList dumpArray(JsonTreeItem *&item) const; + QVariant dumpValue(JsonTreeItem *&item) const; + +private: + JsonTreeItem *theRootItem; +}; + +#endif // JSONTREEMODEL_H diff --git a/chargControlBox_cfgFile.pro b/chargControlBox_cfgFile.pro index 131ce98..0de3c97 100644 --- a/chargControlBox_cfgFile.pro +++ b/chargControlBox_cfgFile.pro @@ -20,10 +20,14 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + JsonTreeItem.cpp \ + JsonTreeModel.cpp \ main.cpp \ mainwindow.cpp HEADERS += \ + JsonTreeItem.h \ + JsonTreeModel.h \ mainwindow.h FORMS += \ diff --git a/chargControlBox_cfgFile.pro.user b/chargControlBox_cfgFile.pro.user index 9c2b202..a8a2bf5 100644 --- a/chargControlBox_cfgFile.pro.user +++ b/chargControlBox_cfgFile.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/mainwindow.cpp b/mainwindow.cpp index 383f094..9ed11b1 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -24,8 +24,32 @@ MainWindow::~MainWindow() void MainWindow::openFile() { - QString s = QFileDialog::getOpenFileName(this,"选择文件","/", "Files(*.json)"); - qDebug() << s << endl; + static QString loadpath; + if (ui->openFile->text() == "打开文件") { + //选择导入的文件路径 + loadpath = QFileDialog::getOpenFileName(this,"选择文件","/", "Files(*.json)"); + qDebug() << loadpath << endl; + + if(loadpath.isEmpty()) return; + jsonModel->loadJson(loadpath); + ui->treeView->expandAll(); + + ui->openFile->setText("保存文件"); + + openFileFlag = true; + + if (openFileFlag && openSerialPortFlag) { + ui->readConfigFile->setEnabled(true); + ui->writeConfigFile->setEnabled(true); + } else { + ui->readConfigFile->setEnabled(false); + ui->writeConfigFile->setEnabled(false); + } + + } else { + if(loadpath.isEmpty()) return; + jsonModel->dumpJson(loadpath); + } } void MainWindow::scanSerialPort() @@ -50,13 +74,28 @@ void MainWindow::parityItemInit() void MainWindow::Init() { + ui->readConfigFile->setEnabled(false); + ui->writeConfigFile->setEnabled(false); + scanSerialPort(); parityItemInit(); serialPort = new QSerialPort(this); + jsonModel = new JsonTreeModel(this); + ui->treeView->setModel(jsonModel); + + openSerialPortFlag = false; + openFileFlag = false; + + connect(ui->openFile,SIGNAL(clicked()),this,SLOT(openFile())); + connect(ui->SerialPortPushButton,SIGNAL(clicked()) ,this,SLOT(openSerialPortPushButtonClicked())); + connect(ui->readConfigFile,SIGNAL(clicked()) + ,this,SLOT(readCfgFile())); + connect(ui->writeConfigFile,SIGNAL(clicked()) + ,this,SLOT(writeCfgFile())); } @@ -133,6 +172,16 @@ void MainWindow::openSerialPortPushButtonClicked() ui->SerialPortPushButton->setText("关闭串口"); ui->label_6->setStyleSheet("color: red;"); // pushButton[0]->setEnabled(true); + + openSerialPortFlag = true; + + if (openFileFlag && openSerialPortFlag) { + ui->readConfigFile->setEnabled(true); + ui->writeConfigFile->setEnabled(true); + } else { + ui->readConfigFile->setEnabled(false); + ui->writeConfigFile->setEnabled(false); + } } } else { @@ -144,5 +193,26 @@ void MainWindow::openSerialPortPushButtonClicked() ui->comboBox_5->setEnabled(true); ui->label_6->setStyleSheet("color: block;"); ui->SerialPortPushButton->setText("打开串口"); + + openSerialPortFlag = false; + + if (openFileFlag && openSerialPortFlag) { + ui->readConfigFile->setEnabled(true); + ui->writeConfigFile->setEnabled(true); + } else { + ui->readConfigFile->setEnabled(false); + ui->writeConfigFile->setEnabled(false); + } } } + +void MainWindow::readCfgFile() +{ + qDebug(" in readCfgFile "); +} + + +void MainWindow::writeCfgFile() +{ + qDebug(" in writeCfgFile "); +} diff --git a/mainwindow.h b/mainwindow.h index fbe372a..b9d9c04 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -8,6 +8,8 @@ #include #include +#include "JsonTreeModel.h" + QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE @@ -25,8 +27,14 @@ private: /* 串口对象 */ QSerialPort *serialPort; + QLineEdit *fileLineEdit; + JsonTreeModel *jsonModel; + + bool openSerialPortFlag; + bool openFileFlag; + void Init(); void scanSerialPort(); void parityItemInit(); @@ -34,6 +42,7 @@ private: private slots: void openFile(); void openSerialPortPushButtonClicked(); - + void readCfgFile(); + void writeCfgFile(); }; #endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui index f06d288..a433b98 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 841 - 665 + 834 + 666 @@ -171,7 +171,14 @@ - + + + + 117 + 20 + + + @@ -461,7 +468,7 @@ 0 0 - 841 + 834 23