【问题标题】:How can I save the file in TreeView as a json file again?如何将 TreeView 中的文件再次保存为 json 文件?
【发布时间】:2019-12-02 10:58:51
【问题描述】:

我可以显示和编辑 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_()

【问题讨论】:

    标签: python pyqt pyqt5 qtreewidget


    【解决方案1】:

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

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

    【讨论】:

    • 感谢您的帮助:) 但我在这部分“fill_item(child, val)”中有一个错误。我不明白为什么。
    • 好吧,如上所述无法测试,但如果它引用 QTreeWidget,则 fill_item 需要“自我”。添加到它的前缀以及与 QTreeWidget 关联的任何其他方法
    • 好的,您将不得不查看您的代码以及我所做的——fill_item 似乎是您的代码中的一个递归调用函数,我在移动它时没有捕获它——我会看看稍后看看我是否能弄清楚如何翻译它——除非你先弄清楚;)
    • 好吧,我想我修复了那段代码——是的,它确实做了一个递归调用,但是在子节点上调用了树的父部分,所以最终它将没有子节点并停止——或者可能不会,但当然需要测试
    猜你喜欢
    • 1970-01-01
    • 2016-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-06
    • 2019-08-12
    • 2015-10-31
    • 2020-08-12
    相关资源
    最近更新 更多