Question

I have a function that reads locations from a text file, parses them, then moves the respective objects to the locations listed on a tkinter canvas using the coords function. The data is being read from the file and parsed correctly but for some reason the coords function is only moving the objects to the last location listed in the file on the last iteration of the loop.

Do I need to update the canvas somehow after each iteration of my loop? Thanks!

Here is my code:

def playback():
    fptr = tkFileDialog.askopenfilename()
    filename = open(fptr,"rU")
    if not filename:
        return

    stat.set('REPLAY IN PROGRESS')
    gamestatus[0] = 2
    for line in filename:
        line = line.strip()

        #Example line from input file: 'B:#,#,#,#|L:#,#,#,#|R:#,#,#,#'
        line = line.split('|')
        B_loc = line[0].split(':')[1].split(',')
        L_loc = line[1].split(':')[1].split(',')
        R_loc = line[2].split(':')[1].split(',')

        #Converting strings to ints and lists to tuples to simplify code below      
        B_tup=(int(B_loc[0]),int(B_loc[1]),int(B_loc[2]),int(B_loc[3]))
        L_tup=(int(L_loc[0]),int(L_loc[1]),int(L_loc[2]),int(L_loc[3]))
        R_tup=(int(R_loc[0]),int(R_loc[1]),int(R_loc[2]),int(R_loc[3]))

        #Moving objects to locations from input file        
        playingField.coords(pongball.ball,B_tup)
        playingField.coords(leftpaddle.paddle,L_tup)
        playingField.coords(rightpaddle.paddle,R_tup)
        time.sleep(.02)

    filename.close()
    gamestatus[0] = 0
    stat.set('-------Pong-------')
Était-ce utile?

La solution

A very good rule of thumb in GUI development is to never call sleep. This freezes the GUI, and even if it's just for a few milliseconds it's still a bad practice.

The proper way to do animation in Tkinter is to write a function that displays a single frame, then reschedules itself using after. This allows the event loop to constantly service events while doing the animation.

For example, take the entire body of the for statement -- minus the sleep -- and put it into a method. Let's call this "refresh". Have this function re-schedule itself using after, like this:

def refresh():
    line = get_next_line()
    line = line.split('|')
    B_loc = line[0].split(':')[1].split(',')
    ...

    # call this function again in 20ms
    root.after(20, refresh)

Now all you need to do is implement get_next_line as a function and you're set. This will automatically allow the GUI to redraw itself each time yo update the coordinates.

Of course, you'll need to put in checks for when input is exhausted, and you might want to have a flag the user can set via a button that requests that the animation stops, etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top