Python : Display a Dict of Dicts using a UI Tree for the keys and any other widget for the values

前端 未结 2 1411
伪装坚强ぢ
伪装坚强ぢ 2020-12-21 17:54

I have three dicts, one providing a list of all the available options, and two providing a subset of choices (one set for defaults and one for user choices). I get the three

相关标签:
2条回答
  • 2020-12-21 18:10

    OK, so it's not really pretty, nor would I feel very good about putting code like this into production, but it does work. To make it more sane and production quality, I'd probably make JSONTree a class with all this code wrapped up into methods. This would allow some simplification and cleanup of the code and a little less passing around of objects to event handlers.

    import json
    import tkinter as tk
    from tkinter import ttk
    from pprint import pprint as pprint
    
    # opt_name: (from_, to, increment)
    IntOptions = {
        'age': (1.0, 200.0, 1.0),
    }
    
    def close_ed(parent, edwin):
        parent.focus_set()
        edwin.destroy()
    
    def set_cell(edwin, w, tvar):
        value = tvar.get()
        w.item(w.focus(), values=(value,))
        close_ed(w, edwin)
    
    def edit_cell(e):
        w = e.widget
        if w and len(w.item(w.focus(), 'values')) > 0:
            edwin = tk.Toplevel(e.widget)
            edwin.protocol("WM_DELETE_WINDOW", lambda: close_ed(w, edwin))
            edwin.grab_set()
            edwin.overrideredirect(1)
            opt_name = w.focus()
            (x, y, width, height) = w.bbox(opt_name, 'Values')
            edwin.geometry('%dx%d+%d+%d' % (width, height, w.winfo_rootx() + x, w.winfo_rooty() + y))
            value = w.item(opt_name, 'values')[0]
            tvar = tk.StringVar()
            tvar.set(str(value))
            ed = None
            if opt_name in IntOptions:
                constraints = IntOptions[opt_name]
                ed = tk.Spinbox(edwin, from_=constraints[0], to=constraints[1],
                    increment=constraints[2], textvariable=tvar)
            else:
                ed = tk.Entry(edwin, textvariable=tvar)
            if ed:
                ed.config(background='LightYellow')
                #ed.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.W, tk.E))
                ed.pack()
                ed.focus_set()
            edwin.bind('<Return>', lambda e: set_cell(edwin, w, tvar))
            edwin.bind('<Escape>', lambda e: close_ed(w, edwin))
    
    def JSONTree(Tree, Parent, Dictionery, TagList=[]):
        for key in Dictionery :
            if isinstance(Dictionery[key], dict):
                Tree.insert(Parent, 'end', key, text=key)
                TagList.append(key)
                JSONTree(Tree, key, Dictionery[key], TagList)
                pprint(TagList)
            elif isinstance(Dictionery[key], list):
                Tree.insert(Parent, 'end', key, text=key) # Still working on this
            else:
                Tree.insert(Parent, 'end', key, text=key, value=Dictionery[key])
    
    if __name__ == "__main__" :
        # Setup the root UI
        root = tk.Tk()
        root.title("JSON editor")
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
        # Setup Data
        Data = {
            "firstName": "John",
            "lastName": "Smith",
            "gender": "man",
            "age": 32,
            "address": {
                "streetAddress": "21 2nd Street",
                "city": "New York",
                "state": "NY",
                "postalCode": "10021"},
            "phoneNumbers": [
                { "type": "home", "number": "212 555-1234" },
                { "type": "fax", "number": "646 555-4567" },
            ]}
        # Setup the Frames
        TreeFrame = ttk.Frame(root, padding="3")
        TreeFrame.grid(row=0, column=0, sticky=tk.NSEW)
        # Setup the Tree
        tree = ttk.Treeview(TreeFrame, columns=('Values'))
        tree.column('Values', width=100, anchor='center')
        tree.heading('Values', text='Values')
        tree.bind('<Double-1>', edit_cell)
        tree.bind('<Return>', edit_cell)
        JSONTree(tree, '', Data)
        tree.pack(fill=tk.BOTH, expand=1)
        # Limit windows minimum dimensions
        root.update_idletasks()
        root.minsize(root.winfo_reqwidth(), root.winfo_reqheight())
        root.mainloop()
    
    0 讨论(0)
  • I've modified John Gaines Jr.'s answer to handle lists. I didn't need editing or the Taglist for what I'm doing so I removed them. They could certainly be added back. Since lists can introduce duplication of keys, I replaced the keys with UUIDs while still showing the original key as text on the left side of the treeview.

    import json
    import uuid
    import Tkinter as tk
    import ttk
    from pprint import pprint as pprint
    
    def JSONTree(Tree, Parent, Dictionary):
        for key in Dictionary :
            uid = uuid.uuid4()
            if isinstance(Dictionary[key], dict):
                Tree.insert(Parent, 'end', uid, text=key)
                JSONTree(Tree, uid, Dictionary[key])
            elif isinstance(Dictionary[key], list):
                Tree.insert(Parent, 'end', uid, text=key + '[]')
                JSONTree(Tree,
                         uid,
                         dict([(i, x) for i, x in enumerate(Dictionary[key])]))
            else:
                value = Dictionary[key]
                if isinstance(value, str) or isinstance(value, unicode):
                    value = value.replace(' ', '_')
                Tree.insert(Parent, 'end', uid, text=key, value=value)
    
    if __name__ == "__main__" :
        # Setup the root UI
        root = tk.Tk()
        root.title("JSON editor")
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
    
        # Setup Data
        Data = {
            "firstName": "John",
            "lastName": "Smith",
            "gender": "male",
            "age": 32,
            "address": {
                "streetAddress": "21 2nd Street",
                "city": "New York",
                "state": "NY",
                "postalCode": "10021"},
            "phoneNumbers": [
                {"type": "home", "number": "212 555-1234" },
                {"type": "fax",
                 "number": "646 555-4567",
                 "alphabet": [
                    "abc",
                    "def",
                    "ghi"]
                }
            ]}
    
        # Setup the Frames
        TreeFrame = ttk.Frame(root, padding="3")
        TreeFrame.grid(row=0, column=0, sticky=tk.NSEW)
    
        # Setup the Tree
        tree = ttk.Treeview(TreeFrame, columns=('Values'))
        tree.column('Values', width=100, anchor='center')
        tree.heading('Values', text='Values')
        JSONTree(tree, '', Data)
        tree.pack(fill=tk.BOTH, expand=1)
    
        # Limit windows minimum dimensions
        root.update_idletasks()
        root.minsize(root.winfo_reqwidth(), root.winfo_reqheight())
        root.mainloop()
    
    0 讨论(0)
提交回复
热议问题