Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter - Modify fill option when using tksvg

Thanks to this question, I discovered tksvg.

I already know how to display an svg file:

import tkinter as tk
import tksvg

window = tk.Tk()
svg_image = tksvg.SvgImage(file="tests/orb.svg")
label = tk.Label(image=svg_image)
label.pack()
window.mainloop()

and also how to do the same using svg data/string:

import tkinter as tk
import tksvg

svg_string = """
<svg aria-hidden="true" focusable="false" role="img" viewBox="0 0 24 24" class="" fill="none" stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><g stroke-width="1.5px" stroke="#B8B8B8" fill="none"><path stroke="none" d="M0 0h24v24H0z" fill="none" stroke-width="1.5px"></path><line x1="4" y1="20" x2="7" y2="20" stroke="#B8B8B8" fill="none" stroke-width="1.5px"></line><line x1="14" y1="20" x2="21" y2="20" stroke="#B8B8B8" fill="none" stroke-width="1.5px"></line><line x1="6.9" y1="15" x2="13.8" y2="15" stroke="#B8B8B8" fill="none" stroke-width="1.5px"></line><line x1="10.2" y1="6.3" x2="16" y2="20" stroke="#B8B8B8" fill="none" stroke-width="1.5px"></line><polyline points="5 20 11 4 13 4 20 20" stroke="#B8B8B8" fill="none" stroke-width="1.5px"></polyline></g></svg>
"""
window = tk.Tk()
svg_image = tksvg.SvgImage(data=svg_string)
label = tk.Label(image=svg_image)
label.pack()
window.mainloop()

but I'm wondering, how do I modify the fill option of the svg element (based on the svg data).

Only way I thought of was to redraw/delete and create the svg element with a different color used in fill. Here is my attempt:

import tkinter as tk
import tksvg

svg_string = '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red"/></svg>'


def change_color(event):
    global svg_string
    fill_color = "blue" if "red" in svg_string else "red"
    svg_string = '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="{}"/></svg>'.format(fill_color)
    canvas.delete(image_store[0])
    svg_store.pop(0)
    svg_store.append(tksvg.SvgImage(data=svg_string))
    image_store[0] = canvas.create_image(100, 100, image=svg_store[0])

window = tk.Tk()
canvas = tk.Canvas(window, width=200, height=200)
canvas.pack()

image_store = []
svg_store = []
svg_store.append(tksvg.SvgImage(data=svg_string))
image_store.append(canvas.create_image(100, 100, image=svg_store[0]))

canvas.tag_bind(image_store[0], "<Button-1>", change_color)
window.mainloop()

Here I tried to switch the color back and forth, so that when it is blue it becomes red, and when red, it becomes blue. But in this case, the color only seems to change once.

I'm only trying to make a workaround since I don't think this is supported yet (feel free to correct me if I'm wrong, as I tried to look at the code, with my best attempt at understanding it at the official github repository).

How can I do this? either using the above workaround (redraw element) or with a better alternative?

I'm on Windows 10, Python version 3.8.10, Tkinter 8.6.9

like image 927
secemp9 Avatar asked May 14 '26 04:05

secemp9


1 Answers

It is because you create a new image item at the same position which covers the previous one and so the mouse click event cannot be triggered because the mouse click is on the new image item which does not have the event binding.

You don't need to create a new image item, just update the current image item instead:

def change_color(event):
    global svg_string
    fill_color = "blue" if "red" in svg_string else "red"
    svg_string = '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="{}"/></svg>'.format(fill_color)
    svg_store.clear()
    svg_store.append(tksvg.SvgImage(data=svg_string))
    # update the current image item instead of creating a new one
    canvas.itemconfig(image_store[0], image=svg_store[0])
like image 89
acw1668 Avatar answered May 15 '26 18:05

acw1668



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!