Home > database >  tkinter: How to continuously redraw an arc in response to slider/spinbox change?
tkinter: How to continuously redraw an arc in response to slider/spinbox change?

Time:01-03

I have a slider and spinbox connected to the same DoubleVar p1. I'm trying to draw an arc that changes position on the canvas as p1 changes.

I tried to draw the arc with arc = myCanvas.create_arc using p1.get() in the parameters, but the arc only draws with p1's initial value of 0, and does not update as the value changes.

Here is an example

import tkinter as tk
from tkinter import ttk
import math

root = tk.Tk()
root.title('Lens')
root.configure(background='#ececec')
root.resizable(False, False)
h = 600
w = 800

myCanvas = tk.Canvas(root, bg="#ececec", height=h, width=w, highlightthickness=0)
y = h/2
x = w/3
r=200

p1 = tk.DoubleVar()


slider1= ttk.Scale(
    root,
    from_=0,
    to=w/2,
    orient='horizontal',
    variable=p1
)

slider1.pack(ipadx=50, padx=0, anchor=tk.NW, side=tk.LEFT)
spin1 = ttk.Spinbox(
    root,
    textvariable=p1,
    wrap=True,
    width=5,
    from_=0,
    to=w/2,
    increment=.01
)
spin1.pack(anchor=tk.NW, side=tk.LEFT)

x1=p1.get()
# lens shape
arc11 = myCanvas.create_arc(x1-1/8*r, y r*math.sqrt(7)/4, x1 7/8*r, y-r*math.sqrt(7)/4, start=90 180/math.pi*math.atan(3/math.sqrt(7)), extent=2*180/math.pi*math.atan(math.sqrt(7)/3), style=tk.ARC)
arc12 = myCanvas.create_arc(x1-7/8*r, y r*math.sqrt(7)/4, x1 1/8*r, y-r*math.sqrt(7)/4, start=90-180/math.pi*math.atan(3/math.sqrt(7)), extent=-2*180/math.pi*math.atan(math.sqrt(7)/3), style=tk.ARC)

myCanvas.pack()
root.mainloop()

CodePudding user response:

You have to explicitly reconfigure the arcs. They won't update just because you update a variable used when initially drawing them.

You can tie a function to the slider, and in that function you can recompute the coordinates and attributes of the arc.

First, create a function to update the coordinates. To keep the example simple I'm just recomputing the data for one arc. Tkinter will pass in the new value, though it will pass it in as a string so it needs to be converted to a float.

def redraw_arcs(*args):
    try:
        x1 = p1.get()
        coords = (x1-7/8*r, y r*math.sqrt(7)/4, x1 1/8*r, y-r*math.sqrt(7)/4)
        myCanvas.coords(arc12, *coords)
    except:
        pass

The try is there, otherwise you'll get an error if the user deletes the data in the spinbox, resulting in an empty string.

Next, put a trace on the variable to call the function when the value changes.

p1.trace_add("write", redraw_arcs)

If you're unfamiliar with how a trace function is called, see What are the arguments to Tkinter variable trace method callbacks?

p1.trace_add("write", redraw_arcs)

If you want to recompute the other attributes such as extent and start, you can use itemconfigure to change those attributes in the function.

CodePudding user response:

You need to update the coordinates of the two arcs whenever the variable p1 is changed by using p1.trace_add():

...
def move_arcs(*args):
    x1 = p1.get()
    myCanvas.coords(arc11, x1-1/8*r, y r*math.sqrt(7)/4, x1 7/8*r, y-r*math.sqrt(7)/4)
    myCanvas.coords(arc12, x1-7/8*r, y r*math.sqrt(7)/4, x1 1/8*r, y-r*math.sqrt(7)/4)

p1.trace_add("write", move_arcs)
root.mainloop()
  • Related