Search code examples
pythondictionarytkintertkinter-canvas

How to copy one tkinter object's options when creating another object of the same type?


I'm trying to draw a rectangle in Tkinter using the options from another rectangle. I cannot hard code the options/which options to get from the first rectangle since I do not know beforehand which options it will have.

I used options = canvas.itemconfig(first) to get a dictionary of the first rectangle's options, then drew the second rectangle using second = canvas.create_rectangle(150, 50, 300, 150, **options) but got the following error:

_tkinter.TclError: bitmap "stipple {} {} {} {}" not defined

I then filtered the options dictionary to remove the parameters with no values (e.g. stipple), but then got the following error message:

_tkinter.TclError: unknown color name "black red"

since outline has two values ("black" and "red") though I gave it only one value while drawing the first rectangle

I also gave the first rectangle two tags, 'rect' and 'orig', which has been changed to 'rect orig'

Here is how the options dictionary looked like before and after filtering the parameters with no values:

Original Dictionary:

{'stipple': ('stipple', '', '', '', ''), 'disabledoutlinestipple': ('disabledoutlinestipple', '', '', '', ''), 'offset': ('offset', '', '', '0,0', '0,0'), 'dash': ('dash', '', '', '', ''), 'disabledwidth': ('disabledwidth', '', '', '0.0', '0'), 'activeoutlinestipple': ('activeoutlinestipple', '', '', '', ''), 'dashoffset': ('dashoffset', '', '', '0', '0'), 'activewidth': ('activewidth', '', '', '0.0', '0.0'), 'fill': ('fill', '', '', '', 'blue'), 'disabledoutline': ('disabledoutline', '', '', '', ''), 'disabledfill': ('disabledfill', '', '', '', ''), 'disableddash': ('disableddash', '', '', '', ''), 'width': ('width', '', '', '1.0', '1.0'), 'state': ('state', '', '', '', ''), 'outlinestipple': ('outlinestipple', '', '', '', ''), 'disabledstipple': ('disabledstipple', '', '', '', ''), 'activedash': ('activedash', '', '', '', ''), 'tags': ('tags', '', '', '', 'rect orig'), 'activestipple': ('activestipple', '', '', '', ''), 'activeoutline': ('activeoutline', '', '', '', ''), 'outlineoffset': ('outlineoffset', '', '', '0,0', '0,0'), 'activefill': ('activefill', '', '', '', ''), 'outline': ('outline', '', '', 'black', 'red')}

Filtered Dictionary:

{'outline': ('black', 'red'), 'width': ('1.0', '1.0'), 'offset': ('0,0', '0,0'), 'disabledwidth': ('0.0', '0'), 'outlineoffset': ('0,0', '0,0'), 'dashoffset': ('0', '0'), 'activewidth': ('0.0', '0.0'), 'tags': ('rect orig',), 'fill': ('blue',)}

And here is the original code:

from Tkinter import *

root = Tk()
canvas = Canvas(root, width=600, height=400)
canvas.pack()

first = canvas.create_rectangle(50, 50, 200, 150, outline="red",
                                fill="blue", tags=("rect", "org"))

options = canvas.itemconfig(first)
print options

#second = canvas.create_rectangle(150, 50, 300, 150, **options)

root.mainloop()

Solution

  • As you can see, itemconfig doesn't return just a dictionary of simple key/value pairs. For each option it will return a tuple made up of the following five items:

    1. option name
    2. option name for the option database
    3. option class for the option database
    4. the default value
    5. the current value

    If you want to replicate all of the options, you need the last item returned for each option.

    You can do that fairly easily with a dictionary comprehension:

    config = canvas.itemconfig(canvas_tag_or_id)
    new_config = {key: config[key][-1] for key in config.keys()}
    canvas.create_rectangle(coords, **new_config)
    

    For more information see