首页 > 解决方案 > 如何将 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_()

在此处输入图像描述

标签: pythonpyqtpyqt5qtreewidget

解决方案


好的,我没有方便的 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_())

最后一点,我没有测试/验证你的代码,因为我假设你理解它的作用,并且会理解如何调整它,如果它需要调整以使用这个框架


推荐阅读