0

I want to save canvas all "object" not the graph of canvas to save. And load the saving to modify the object(maybe change position,color) I know that is no way to save widget object by pickle. So I want to save the entire config of object and recreate object when loading. Is any one know how to achieve pickle_save/pickle_load this two function which will load/save self.c.

from tkinter.ttk import *
from tkinter import *
import tkinter.filedialog
import pickle



class Test_Gui(Frame):

   def __init__(self, root, run_class=None):

      Frame.__init__(self, root)
      self.run_class = run_class
      self.root = root
      root.geometry("+400+50")
      root.title("This is ping status")
      self.width = 600
      self.height = 400

      # create canvas at begin will be saved or replace by loading 
      self.c = Canvas(self, width=self.width, height=self.height,
                      bd=0, bg="green", highlightthickness=5, relief=RIDGE, borderwidth=2,
                      scrollregion=(0, 0, self.width, self.height))
      self.c.pack()
      self.canvas_bind()
      self.setting_menu()

      self.pack()

   def setting_menu(self):

      self.rootmenu = Menu(self.root, tearoff=False)
      self.root.config(menu=self.rootmenu)
      openmenu = Menu(self.rootmenu, tearoff=False)
      self.rootmenu.add_cascade(label='Open', menu=openmenu, underline=0)

      def pickle_save():
         # Some method to save widget object/config
         # save self.c to file
         pass

      def pickle_load():
         # Some method to loading save
         # destory self.c or origin and load file  tot self.c
         pass


      openmenu.add_command(label='Save', command=pickle_save)
      openmenu.add_command(label='Load', command=pickle_load)
      openmenu.add_command(label='Exit', command=self.root.destroy)

   def canvas_bind(self):
      def left_click(event):
         x, y = self.c.canvasx(event.x), self.c.canvasx(event.y)
         x1, y1 = (x - 3), (y - 3)
         x2, y2 = (x + 3), (y + 3)
         self.c.create_oval(x1, y1, x2, y2, fill="red")
      self.c.bind('<Button-1>', left_click)



if __name__ == '__main__':
   root = Tk()
   root.bind("<Escape>", lambda *x: root.destroy())
   root.geometry("300x200+50+50")

   top = Toplevel(root)
   Test_Gui(root=top)

   root.mainloop()
黃瀚嶙
  • 167
  • 1
  • 10
  • Does this answer your question? [Saving canvas from tkinter to file](https://stackoverflow.com/questions/41940945/saving-canvas-from-tkinter-to-file) – metatoaster Jul 22 '20 at 02:23
  • @metatoaster nope ,I want to save "Object" not "Picture". – 黃瀚嶙 Jul 22 '20 at 02:28
  • Your `Test_Gui` class will recreate the `Canvas` object when it's created, so you need to explain what exactly do you mean by "saving canvas object" because the way your program is set up isn't aligned to your intent (your program is creating the `Canvas`, thus no need to "save the canvas", but you don't want to save the Picture, so what are you doing?), and your unclear intent makes it difficult for those who are reading the question to deduce exactly what you are after. – metatoaster Jul 22 '20 at 02:43
  • @metatoaster , This "Test_Gui" will create canvas at first,so user can save after they modify the canvas or loading canvas just like notepad. "Test_Gui" didn't "recreate" canvas object. – 黃瀚嶙 Jul 22 '20 at 02:50
  • @metatoaster But you are right, I should make problem more readable,so I add more comment in question. – 黃瀚嶙 Jul 22 '20 at 02:56
  • But you see, The editing pane of `notepad.exe` isn't pickled or saved whatsoever into the text file that the user has saved after editing - the raw content (in this case text) in that editing pane is saved into a file when user saves it. When a user load a file, `notepad.exe` will load the file as text into the editing pane to display to user. What you want is indeed the ability to save the image in the canvas on saving, and [draw it back into that canvas](https://stackoverflow.com/questions/46388292/drawing-a-png-image-on-a-tkinter-canvas-python) when a user loads it. – metatoaster Jul 22 '20 at 03:38

1 Answers1

2

Use json to save the canvas items to a text file:

import json
...

self.json_file = 'canvas-items.json'

def json_save():
    with open(self.json_file, 'w') as f:
        for item in self.c.find_all():
            print(json.dumps({
                'type': self.c.type(item),
                'coords': self.c.coords(item),
                'options': {key:val[-1] for key,val in self.c.itemconfig(item).items()}
            }), file=f)

Then you can read the json file and create the items:

def json_load():
    # if you want to clear the canvas first, uncomment below line
    #self.c.delete('all')
    funcs = {
        'arc': self.c.create_arc,
        #'bitmap' and 'image' are not supported
        #'bitmap': self.c.create_bitmap,
        #'image': self.c.create_image,
        'line': self.c.create_line,
        'oval': self.c.create_oval,
        'polygon': self.c.create_polygon,
        'rectangle': self.c.create_rectangle,
        'text': self.c.create_text,
         # 'window' is not supported
    }
    with open(self.json_file) as f:
        for line in f:
            item = json.loads(line)
            if item['type'] in funcs:
                funcs[item['type']](item['coords'], **item['options'])


openmenu.add_command(label='Save', command=json_save)
openmenu.add_command(label='Load', command=json_load)
acw1668
  • 40,144
  • 5
  • 22
  • 34