递归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("<Double-Button-1>", self.add_node)
    self.canvas.bind("<Button-3>", 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, "<Button-1>", 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  阅读(31)  评论(0)    收藏  举报