使用json配置

This commit is contained in:
起床就犯困 2025-01-16 09:10:46 +08:00
parent 9aa354ffbc
commit fbd1be96d8
9 changed files with 700 additions and 8 deletions

163
JsonTreeItem.cpp Normal file
View File

@ -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<int, QVariant> &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;i<count;i++){
JsonTreeItem *item=new JsonTreeItem(this);
//目前还没有delegate来自定义操作所以new item默认为json Value类型
item->setType(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;i<count;i++){
delete theChildItems.takeAt(row+i);
}
return true;
}
void JsonTreeItem::appendChild(JsonTreeItem *child)
{
theChildItems.append(child);
child->setParentItem(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<JsonTreeItem*>(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;
}

63
JsonTreeItem.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef JSONTREEITEM_H
#define JSONTREEITEM_H
#include <QList>
//对于多种结构可以写一个item抽象父类
//我这个Item比较简单基本都是靠外部来设置
class JsonTreeItem
{
public:
//item的类型None为无效的类型
enum JsonItemType{
None,
Object,
Array,
Value
};
public:
explicit JsonTreeItem(JsonTreeItem *parent=nullptr);
explicit JsonTreeItem(const QHash<int,QVariant> &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<int,QByteArray> 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<JsonTreeItem*> theChildItems; //append来添加child
JsonItemType theItemType;
//hash内容
//1key
//2value
//用hash是为了便于扩展比如增加勾选列等
//如果只是简单的key+value两行数据就用QString+QVariant就行了
QHash<int,QVariant> theItemDatas; //存放每列角色的内容qml的tree使用角色
};
#endif // JSONTREEITEM_H

313
JsonTreeModel.cpp Normal file
View File

@ -0,0 +1,313 @@
#include "JsonTreeModel.h"
#include <QVariantMap>
#include <QFile>
#include <QDebug>
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;
//转换为bytearrayCompact没有换行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<JsonTreeItem*>(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:"<<item_key;
parseValue(item_key,obj.value(item_key),child);
}
}
void JsonTreeModel::parseArray(const QString &key, const QJsonArray &arr, JsonTreeItem *&item)
{
//构造Array节点
JsonTreeItem *child=new JsonTreeItem({{0,key},{1,"[Array]"}},JsonTreeItem::Array,item);
item->appendChild(child);
//遍历Array
for(int i=0;i<arr.count();i++){
parseValue("-",arr.at(i),child);
}
}
void JsonTreeModel::parseValue(const QString &key, const QJsonValue &val, JsonTreeItem *&item)
{
QVariant the_val;
//根据Value的类型进行下一步处理
//如果是Object或Array就继续递归
//如果是值就添加一个节点
switch (val.type()) {
case QJsonValue::Object:
parseObject(key,val.toObject(),item);
return;
break;
case QJsonValue::Array:
parseArray(key,val.toArray(),item);
return;
break;
case QJsonValue::Bool:
the_val=val.toBool();
break;
case QJsonValue::Double:
the_val=val.toDouble();
break;
case QJsonValue::String:
the_val=val.toString();
break;
case QJsonValue::Null: break;
case QJsonValue::Undefined: break;
default: break;
}
//构造子节点
JsonTreeItem *child=new JsonTreeItem({{0,key},{1,the_val}},JsonTreeItem::Value,item);
item->appendChild(child);
}
QVariantMap JsonTreeModel::dumpObject(JsonTreeItem *&item) const
{
QVariantMap json_obj; //QVariantMap对应QJsonObject
const int child_count=item->childCount();
for(int i=0;i<child_count;i++){
JsonTreeItem *child=item->childItem(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;i<child_count;i++){
JsonTreeItem *child=item->childItem(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();
}

63
JsonTreeModel.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef JSONTREEMODEL_H
#define JSONTREEMODEL_H
#include <QAbstractItemModel>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QVariant>
#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<int,QByteArray> 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

View File

@ -20,10 +20,14 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \ SOURCES += \
JsonTreeItem.cpp \
JsonTreeModel.cpp \
main.cpp \ main.cpp \
mainwindow.cpp mainwindow.cpp
HEADERS += \ HEADERS += \
JsonTreeItem.h \
JsonTreeModel.h \
mainwindow.h mainwindow.h
FORMS += \ FORMS += \

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.12.2, 2025-01-10T18:18:42. --> <!-- Written by QtCreator 4.12.2, 2025-01-11T17:55:05. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

View File

@ -24,8 +24,32 @@ MainWindow::~MainWindow()
void MainWindow::openFile() void MainWindow::openFile()
{ {
QString s = QFileDialog::getOpenFileName(this,"选择文件","/", "Files(*.json)"); static QString loadpath;
qDebug() << s << endl; 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() void MainWindow::scanSerialPort()
@ -50,13 +74,28 @@ void MainWindow::parityItemInit()
void MainWindow::Init() void MainWindow::Init()
{ {
ui->readConfigFile->setEnabled(false);
ui->writeConfigFile->setEnabled(false);
scanSerialPort(); scanSerialPort();
parityItemInit(); parityItemInit();
serialPort = new QSerialPort(this); 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->openFile,SIGNAL(clicked()),this,SLOT(openFile()));
connect(ui->SerialPortPushButton,SIGNAL(clicked()) connect(ui->SerialPortPushButton,SIGNAL(clicked())
,this,SLOT(openSerialPortPushButtonClicked())); ,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->SerialPortPushButton->setText("关闭串口");
ui->label_6->setStyleSheet("color: red;"); ui->label_6->setStyleSheet("color: red;");
// pushButton[0]->setEnabled(true); // 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 { } else {
@ -144,5 +193,26 @@ void MainWindow::openSerialPortPushButtonClicked()
ui->comboBox_5->setEnabled(true); ui->comboBox_5->setEnabled(true);
ui->label_6->setStyleSheet("color: block;"); ui->label_6->setStyleSheet("color: block;");
ui->SerialPortPushButton->setText("打开串口"); 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 ");
}

View File

@ -8,6 +8,8 @@
#include <QLineEdit> #include <QLineEdit>
#include <QGridLayout> #include <QGridLayout>
#include "JsonTreeModel.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; } namespace Ui { class MainWindow; }
QT_END_NAMESPACE QT_END_NAMESPACE
@ -25,8 +27,14 @@ private:
/* 串口对象 */ /* 串口对象 */
QSerialPort *serialPort; QSerialPort *serialPort;
QLineEdit *fileLineEdit; QLineEdit *fileLineEdit;
JsonTreeModel *jsonModel;
bool openSerialPortFlag;
bool openFileFlag;
void Init(); void Init();
void scanSerialPort(); void scanSerialPort();
void parityItemInit(); void parityItemInit();
@ -34,6 +42,7 @@ private:
private slots: private slots:
void openFile(); void openFile();
void openSerialPortPushButtonClicked(); void openSerialPortPushButtonClicked();
void readCfgFile();
void writeCfgFile();
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>841</width> <width>834</width>
<height>665</height> <height>666</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -171,7 +171,14 @@
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QComboBox" name="SerialPort"/> <widget class="QComboBox" name="SerialPort">
<property name="maximumSize">
<size>
<width>117</width>
<height>20</height>
</size>
</property>
</widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
@ -461,7 +468,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>841</width> <width>834</width>
<height>23</height> <height>23</height>
</rect> </rect>
</property> </property>