我有三个字典,一个提供所有可用选项的列表,另外两个提供选择的子集(一个用于默认设置,一个用于用户选择)。我使用python内置的JSON解析器获得了三个字典。
我想在UI中在左边显示一棵基于字典中键的树,在右边我想显示一个组合框,一个按钮,一个列表框或一些其他适当的小部件来处理数据那把钥匙。我需要这棵树,因为我实际上是在做一份字典,并且我想允许折叠。
到目前为止,我已经研究了tkinter,tkinter的ttk和tix库,它们似乎允许树,但不允许在右边显示可配置列表。我还看到了一些从python的IDLE借来树的示例。
如果GUI工具包是跨平台兼容的(* nix和win),并且在可能的情况下可以免费分发,我会更喜欢它。出于兴趣,这里没有关于使用tk创建自定义窗口小部件的教程,我尝试过查找,但是我一直直接针对tk的窗口小部件使用,而不是窗口小部件设计:s
作为一个最小的示例,我暂时放弃了额外的命令,并具有以下内容:
import json import tkinter as tk from tkinter import ttk from pprint import pprint as pprint 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') 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()
好吧,所以它不是很漂亮,将这样的代码投入生产也不会感到很好,但是它确实可以工作。为了使其更加理智和提高生产质量,我可能将JSONTree设置为一个类,并将所有这些代码包装到方法中。这样可以简化和清除代码,并减少将对象传递给事件处理程序的过程。
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()