递归json可视化

import tkinter as tk
from tkinter import simpledialog, filedialog, messagebox
import json

class TreeEditor:
def init(self, root):
self.root = root
self.root.title("Tree Editor")

Canvas for drawing

self.canvas = tk.Canvas(root, bg="white", width=800, height=600)
self.canvas.pack(fill=tk.BOTH, expand=True)

Menus

self.menu = tk.Menu(root)
root.config(menu=self.menu)
self.file_menu = tk.Menu(self.menu, tearoff=0)
self.file_menu.add_command(label="Open JSON", command=self.load_json)
self.file_menu.add_command(label="Save JSON", command=self.save_json)
self.menu.add_cascade(label="File", menu=self.file_menu)

Data structures

self.nodes = {} # node_id -> {"data": node_data, "oval": canvas_id, "text": canvas_id}
self.current_node_id = 0
self.connections = [] # (start_node_id, end_node_id)

Event bindings

self.canvas.bind("", self.add_node)
self.canvas.bind("", self.delete_node)

def add_node(self, event):
"""Add a new node."""
x, y = event.x, event.y
key = simpledialog.askstring("Node Key", "Enter key:")
result = simpledialog.askstring("Node Result", "Enter result:")
if key and result:
node_data = {"key": key, "result": result, "next": []}
self.draw_node(node_data, x, y)

def draw_node(self, node_data, x, y):
"""Draw a node and add it to the structure."""
node_id = self.current_node_id
self.current_node_id += 1

Draw the node

radius = 30
oval = self.canvas.create_oval(x-radius, y-radius, x+radius, y+radius, fill="lightblue")
text = self.canvas.create_text(x, y, text=f"{node_data['key']}\n{node_data['result']}")

Bind editing to the node

self.canvas.tag_bind(oval, "", lambda e, nid=node_id: self.edit_node(nid))

Save the node

self.nodes[node_id] = {"data": node_data, "oval": oval, "text": text}

def delete_node(self, event):
"""Delete a node and its connections."""
x, y = event.x, event.y
node_id = self.get_node_at_position(x, y)
if node_id is not None:
# Remove from canvas
self.canvas.delete(self.nodes[node_id]["oval"])
self.canvas.delete(self.nodes[node_id]["text"])

Remove connections

self.connections = [(s, e) for s, e in self.connections if s != node_id and e != node_id]

Remove from data

del self.nodes[node_id]

def edit_node(self, node_id):
"""Edit the node's key and result."""
node = self.nodes[node_id]
key = simpledialog.askstring("Edit Key", "Enter new key:", initialvalue=node["data"]["key"])
result = simpledialog.askstring("Edit Result", "Enter new result:", initialvalue=node["data"]["result"])
if key and result:
node["data"]["key"] = key
node["data"]["result"] = result
self.canvas.itemconfig(node["text"], text=f"{key}\n{result}")

def get_node_at_position(self, x, y):
"""Get the node at the given canvas position."""
for node_id, node in self.nodes.items():
x1, y1, x2, y2 = self.canvas.coords(node["oval"])
if x1 <= x <= x2 and y1 <= y <= y2:
return node_id
return None

def load_json(self):
"""Load JSON data and visualize."""
filepath = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")])
if filepath:
with open(filepath, "r") as f:
data = json.load(f)
self.nodes.clear()
self.connections.clear()
self.canvas.delete("all")
self.current_node_id = 0
self.visualize(data, 400, 50, 200)

def visualize(self, data, x, y, x_offset):
"""Recursively visualize JSON data."""
node_id = self.current_node_id
self.current_node_id += 1

Draw node

self.draw_node(data, x, y)

Draw children

for child in data.get("next", []):
child_id = self.current_node_id
self.visualize(child, x-x_offset, y+100, x_offset//2)

Draw connection

start_coords = self.canvas.coords(self.nodes[node_id]["oval"])
end_coords = self.canvas.coords(self.nodes[child_id]["oval"])
start_x, start_y = (start_coords[0] + start_coords[2]) / 2, (start_coords[1] + start_coords[3]) / 2
end_x, end_y = (end_coords[0] + end_coords[2]) / 2, (end_coords[1] + end_coords[3]) / 2
self.connections.append((node_id, child_id))
self.canvas.create_line(start_x, start_y, end_x, end_y, arrow=tk.LAST)

def save_json(self):
"""Save the current nodes and connections to JSON."""
filepath = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("JSON files", "*.json")])
if filepath:
def build_json(node_id):
node = self.nodes[node_id]["data"]
children = [build_json(child_id) for _, child_id in self.connections if _ == node_id]
node["next"] = children
return node

Find the root node (no parent)

root_id = next(iter(self.nodes))
data = build_json(root_id)

with open(filepath, "w") as f:
json.dump(data, f, indent=4)

if name == "main":
root = tk.Tk()
app = TreeEditor(root)
root.mainloop()

posted @ 2025-01-03 09:45  MingYu15  阅读(58)  评论(0)    收藏  举报