Search code examples
pythonuser-interfacetkinterupdatestrace

Why doesn't the GUI update even with trace and a callback function?


I'm having a bit of trouble figuring out why the following code doesn't update even though I'm using a tkinter variable, the .trace method and the .update method.

    from tkinter import *
    from math import sin, cos, pi
    master = Tk()


    people_size_var = IntVar()

    PeopleSize = Scale(master, from_=1, to=50, bd=3, length=153, variable=people_size_var)
    PeopleSize.grid(row=2, column=4, padx=10, pady=5)
    people_size_var.set(20)
    PeopleSize.config(highlightbackground="white")

    def update_canvas(*args):
        DisplayFrame.update()

    people_size_var.trace("w", update_canvas)

    a = 350
    b = 140
    ellipsePoints = [(a * cos(theta), b * sin(theta))
                     for theta in (pi*2 * i/number_of_people for i in range(number_of_people))]
    DisplayFrame = Canvas(master, bg="white", width=725, height=320)
    DisplayFrame.grid(row=0, columnspan=7, column=0, sticky='W', padx=5, pady=5)


    for i in range(number_of_people-1):
        Bonds = DisplayFrame.create_line(ellipsePoints[i][0]+355+(node_size/2), ellipsePoints[i][1]+155+(node_size/2),
                                 ellipsePoints[i+1][0]+355+(node_size/2), ellipsePoints[i+1][1] +155+(node_size/2),
                                 width=2, fill="black")

    for i in range(number_of_people):
        People = DisplayFrame.create_oval(ellipsePoints[i][0]+355, ellipsePoints[i][1]+155,
                                 ellipsePoints[i][0]+355 + node_size, ellipsePoints[i][1] + 155 + node_size,
                                 fill="yellow", outline="black", width=2)





    master.mainloop()

So, as you can see my code draws some circles and lines between those circles in a Canvas (DisplayFrame). I try to update the canvas every time the people_size_var changes, but it just doesn't work. The trace does work, just the update function doesn't. I am still new to all this tkinter stuff so I don't really know how to figure out what's wrong with the code. There are no errors whatsoever written in the terminal.


Solution

  • I don't think you need to use update() method here. You already have an infinite loop running, the main(event) loop. You can just use it.

    Since you want to draw whole thing on every scale change, you need to put drawing stuff in your callback but be sure not to create another canvas on each callback, so you need to put creating canvas stuff outside of the function and clear the canvas everytime to draw new stuff on it.

    I assumed node_size is a constant and number_of_people changes with scale.

    from tkinter import *
    from math import sin, cos, pi
    master = Tk()
    
    def update_canvas(*args):
        number_of_people = people_size_var.get() #gets scale's value
        DisplayFrame.delete("all") #deletes every content from canvas
    
        a = 350
        b = 140
        ellipsePoints = [(a * cos(theta), b * sin(theta))
                         for theta in (pi*2 * i/number_of_people for i in range(number_of_people))]
    
        for i in range(number_of_people-1):
            Bonds = DisplayFrame.create_line(ellipsePoints[i][0]+355+(node_size/2), ellipsePoints[i][1]+155+(node_size/2),
                                     ellipsePoints[i+1][0]+355+(node_size/2), ellipsePoints[i+1][1] +155+(node_size/2),
                                     width=2, fill="black")
    
        for i in range(number_of_people):
            People = DisplayFrame.create_oval(ellipsePoints[i][0]+355, ellipsePoints[i][1]+155,
                                     ellipsePoints[i][0]+355 + node_size, ellipsePoints[i][1] + 155 + node_size,
                                     fill="yellow", outline="black", width=2)
    
    people_size_var = IntVar()
    PeopleSize = Scale(master, from_=1, to=50, bd=3, length=320, variable=people_size_var)
    PeopleSize.grid(row=0, column=0, padx=10, pady=5)
    people_size_var.set(20)
    PeopleSize.config(highlightbackground="white")
    
    node_size = 5
    
    DisplayFrame = Canvas(master, bg="white", width=725, height=320)
    DisplayFrame.grid(row=0, columnspan=7, column=1, sticky='W', padx=5, pady=5)
    
    people_size_var.trace("w", update_canvas)
    
    master.mainloop()