python - 如何将 TreeView 中的文件再次保存为 json 文件?
问题描述
我可以以 QTreeWidget 形式显示和编辑 json 文件。如何在桌面上再次保存这个编辑过的 json 文件。
我的目标是创建一个我们可以编辑的 json 编辑器
import json
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
class ViewTree(QTreeWidget):
def __init__(self, value):
super().__init__()
def fill_item(item, value):
def new_item(parent, text, val=None):
child = QTreeWidgetItem([text])
child.setFlags(child.flags() | Qt.ItemIsEditable)
fill_item(child, val)
parent.addChild(child)
child.setExpanded(True)
if value is None: return
elif isinstance(value, dict):
for key, val in sorted(value.items()):
new_item(item, str(key), val)
elif isinstance(value, (list, tuple)):
for val in value:
text = (str(val) if not isinstance(val, (dict, list, tuple))
else '[%s]' % type(val).__name__)
new_item(item, text, val)
else:
new_item(item, str(value))
fill_item(self.invisibleRootItem(), value)
if __name__ == '__main__':
app = QApplication([])
fname = QFileDialog.getOpenFileName()
json_file=open(fname[0],"r")
file=json.load(json_file)
window = ViewTree(file)
window.setGeometry(300, 100, 900, 600)
window.show()
app.exec_()
解决方案
好的,我没有方便的 Json 文件来测试它,但我拿走了你的代码并对其进行了一些转换。现在,当您在 TreeWidget 中进行任何更改时,您正在处理 JsonTable 和 TreeWidget,您只需使用这些更改更新 JsonTable。这段代码并不完整,你仍然需要自己渲染一些部分,但它应该为你提供一个可靠的模板来构建,以及一些你可能不知道的漂亮功能;)
import json
import argparse
from sys import exit as sysExit
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTreeWidget, QFileDialog, QDockWidget, QAction
class MenuToolBar(QDockWidget):
def __init__(self, MainWin):
QDockWidget.__init__(self)
self.MainWin = MainWin
self.MainMenu = MainWin.menuBar()
self.MenuActRef = {'OpnJsonAct':0,
'SavJsonAct':0}
# ******* Create the File Menu *******
self.FileMenu = self.MainMenu.addMenu('File')
# ******* Create File Menu Items *******
# self.OpnJsonAct = QAction(QIcon('Images/open.ico'), '&Open', self)
self.OpnJsonAct = QAction('&Open', self)
self.OpnJsonAct.setShortcut("Ctrl+O")
self.OpnJsonAct.setStatusTip('Open an Existing Json File')
self.OpnJsonAct.triggered.connect(self.GetJsonFile)
self.MenuActRef['OpnJsonAct'] = self.OpnJsonAct
# self.SavJsonAct = QAction(QIcon('Images/save.ico'), '&Save', self)
self.SavJsonAct = QAction('&Save', self)
self.SavJsonAct.setShortcut("Ctrl+S")
self.SavJsonAct.setStatusTip('Open an Existing Json File')
self.SavJsonAct.triggered.connect(self.SaveJsonFile)
self.MenuActRef['SavJsonAct'] = self.SavJsonAct
# ******* Setup the File Menu *******
self.FileMenu.addAction(self.OpnJsonAct)
self.FileMenu.addSeparator()
self.FileMenu.addAction(self.SavJsonAct)
def GetJsonFile(self):
self.MainWin.OpenFile()
def SaveJsonFile(self):
self.MainWin.SaveFile()
class ViewTree(QTreeWidget):
def __init__(self, parent):
QTreeWidget.__init__(self)
self.MyParent = parent
self.TreeRoot = self.invisibleRootItem()
# Just to show you what a static method looks like
# one that does not need a reference to self because
# it does not use self -- non-essential you can
# delete this when you are done testing with it
@staticmethod
def PrintTree():
print('Tree View Ready')
def FillTree(self):
if self.JSonTable is None:
pass
elif isinstance(self.JSonTable, dict):
for key, val in sorted(self.JSonTable.items()):
self.new_item(self.TreeRoot, str(key), val)
elif isinstance(self.JSonTable, (list, tuple)):
for val in self.JSonTable:
text = (str(val) if not isinstance(val, (dict, list, tuple))
else '[%s]' % type(val).__name__)
self.new_item(self.TreeRoot, text, val)
else:
self.new_item(self.TreeRoot, str(self.JSonTable))
def new_item(self, text, val=None):
child = QTreeWidgetItem([text])
child.setFlags(child.flags() | Qt.ItemIsEditable)
self.FillTree(child, val)
self.addChild(child)
child.setExpanded(True)
# This is meant to capture the On Change Event for the QTreeWidget
def OnChange(self):
print('Handling Changes Here for:',self.MyParent.JSonTable)
# This routine would update your JsonTable with any changes
# that take place within your TreeWidget however I do not
# think this is the correct function name to capture that
# event so you might have to research this one a bit to get
# the appropriate name
class MainWindow(QMainWindow):
def __init__(self, JsonFilePath):
super(MainWindow, self).__init__()
self.setWindowTitle('Json File Editor')
self.setGeometry(300, 100, 900, 600)
self.JsonFile = JsonFilePath
self.JSonTable = None
self.CenterPane = ViewTree(self)
self.setCentralWidget(self.CenterPane)
self.CenterPane.PrintTree()
# Rem'd out because I could not test this for you
# However it should work or... it might need tweaks
# if len(self.JsonFile) > 0:
# self.LoadFile()
self.MainMenu = MenuToolBar(self)
def OpenFile():
self.JsonFile = QFileDialog.getOpenFileName()
# Do not recall if QFileDialog returns None or not so you need to check that
if len(self.JsonFile) > 0:
self.LoadFile()
def LoadFile():
# Note one should always validate that they have a valid file prior to opening it
# isfile() -- and checking the file extension are two methods I use
JsonData = open(self.JsonFile[0],"r")
self.JSonTable = json.load(JsonData)
self.CenterPane.FillTree(self.JSonTable)
def SaveFile():
# Either to a new file or overwriting the exiting file
# but basically you are now just saving your JsonTable
# to file -- you could just loop through it manually or
# I think there are wheels already invented to handle
# Json objects like this and print them out to a file
print('Saving Jason File')
def CmdLine():
# create Parser object
Parser = argparse.ArgumentParser(description = "Load this Json File - Given the full file path")
# defining arguments for Parser object
Parser.add_argument('-f', '--filepath', type = str, help = "This specifies the full path and filename for the Json File.")
# parse the argument if any from standard input
CmdLineVal = Parser.parse_args().filepath
RetVal = ''
if CmdLineVal != None:
RetVal = CmdLineVal
return RetVal
if __name__ == '__main__':
JsonFilePath = CmdLine()
MainThred = QApplication([])
MainGUI = MainWindow(JsonFilePath)
MainGUI.show()
sysExit(MainThred.exec_())
最后一点,我没有测试/验证你的代码,因为我假设你理解它的作用,并且会理解如何调整它,如果它需要调整以使用这个框架
推荐阅读
- wpf - WPF DataGrid - 禁用 DataGridCheckBoxColumn
- json - Azure ARM模板中concat函数和资源id函数的区别
- debian - wlan0:通过本地选择取消身份验证
- google-cloud-platform - 解决“超出配额 N2_CPUS”
- excel - 定位分配有宏的条纹右箭头
- jquery - 如何使用多个收音机在 jquery 中隐藏/显示内容
- angular - Angular 控制台错误未通过单元测试
- encryption - 加密数据是否包含空格?
- input - isNumberKey 与 truncateDecimals 结合导致输入字段中出现异常舍入
- latex - 在 Latex 投影仪中,如何在幻灯片上绘制大箭头