I'm trying to make a save function in a program im doing for bubbling/ballooning drawings. The only thing I can't get to work is save a "work copy". As if a drawing gets revision changes, you don't need to redo all the work. Just load the work copy, and add/remove/re-arrage bubbles.
I'm using tkinter and canvas. And creates ovals and text for bubbles. But I can't figure out any good way to save the info from the oval/text objects. I tried to pickle the whole canvas, but that seems like it won't work after some googeling. And pickle every object when created seems to only save the object id. 1, 2 etc. And that also won't work since some bubbles will be moved and receive new coordinates. They might also have a different color, size etc.
In my next approach I'm thinking of saving the whole "can.create_oval( x1, y1, x2, y2, fill = fillC, outli...." as a string to a txt and make the function to recreate a with eval()
Any one have any good suggestion on how to approach this?
Answer
To save the state of your drawings on a tkinter.Canvas
and allow for loading and continuing work, you need to serialize the necessary information for each drawable element (e.g., ovals, text, etc.) to a file and then use that data to reconstruct the canvas later.
Here’s how you can approach this:
Step 1: Serialize Canvas Objects
You can extract the attributes of each object on the canvas and save them in a structured format like JSON. JSON is human-readable and easy to work with.
For example:
- Ovals: Store their bounding box (
x1, y1, x2, y2
), fill color, outline color, and other properties. - Text: Store its position, content, font, color, etc.
Step 2: Save to File
Write the serialized data to a file. You can save it as a .json
file for easy reloading.
Step 3: Load from File
When loading the file, parse the JSON data and use it to recreate the objects on the canvas.
Example Implementation
Here’s a simple example:
import tkinter as tk
import json
class BubbleApp:
def __init__(self, root):
self.root = root
self.canvas = tk.Canvas(root, width=800, height=600, bg="white")
self.canvas.pack()
self.objects = [] # Store the objects and their properties
self.create_buttons()
def create_buttons(self):
save_btn = tk.Button(self.root, text="Save Work", command=self.save_work)
save_btn.pack(side="left")
load_btn = tk.Button(self.root, text="Load Work", command=self.load_work)
load_btn.pack(side="left")
create_btn = tk.Button(self.root, text="Create Bubble", command=self.create_bubble)
create_btn.pack(side="left")
def create_bubble(self):
x1, y1, x2, y2 = 100, 100, 200, 200
fill = "lightblue"
outline = "blue"
oval = self.canvas.create_oval(x1, y1, x2, y2, fill=fill, outline=outline)
text = self.canvas.create_text((x1 + x2) // 2, (y1 + y2) // 2, text="Bubble")
# Save properties for reconstruction
self.objects.append({
"type": "oval",
"coords": (x1, y1, x2, y2),
"fill": fill,
"outline": outline,
})
self.objects.append({
"type": "text",
"coords": ((x1 + x2) // 2, (y1 + y2) // 2),
"text": "Bubble",
})
def save_work(self):
with open("work_copy.json", "w") as f:
json.dump(self.objects, f, indent=4)
print("Work saved to 'work_copy.json'")
def load_work(self):
self.canvas.delete("all") # Clear the canvas
with open("work_copy.json", "r") as f:
self.objects = json.load(f)
# Recreate objects on the canvas
for obj in self.objects:
if obj["type"] == "oval":
self.canvas.create_oval(
*obj["coords"],
fill=obj["fill"],
outline=obj["outline"]
)
elif obj["type"] == "text":
self.canvas.create_text(
*obj["coords"],
text=obj["text"]
)
print("Work loaded from 'work_copy.json'")
# Run the app
root = tk.Tk()
app = BubbleApp(root)
root.mainloop()
Key Points:
-
Serialization:
- Store all necessary attributes for each object in a structured format.
- JSON is a good choice for saving the data.
-
Reconstruction:
- Use the saved data to recreate the canvas objects by calling the appropriate
canvas.create_*
methods.
- Use the saved data to recreate the canvas objects by calling the appropriate
-
Extensibility:
- You can easily extend this approach to support other types of objects (e.g., rectangles, lines) or additional properties like tags or fonts.
-
No
eval()
:- Using
eval()
to reconstruct objects from strings is dangerous and unnecessary. JSON or another structured format is safer and more robust.
- Using
This approach ensures that you can save, load, and modify your canvas drawings seamlessly without relying on unsafe practices.