'Refreshing a tkinter window

Code:

import tkinter, urllib.request, json, io
from PIL import Image, ImageTk
main = tkinter.Tk()
main.geometry('500x500+800+300')
dogapi = urllib.request.urlopen(f'https://dog.ceo/api/breeds/image/random')
dogjson = dogapi.read()
dogdict = json.loads(dogjson)
url=dogdict['message']
m = urllib.request.urlopen(url)
mp = io.BytesIO(m.read())
mpi = Image.open(mp)
tkimg = ImageTk.PhotoImage(mpi)
l = tkinter.Label(main, image=tkimg)
b = tkinter.Button(main, text='Next Dog', command='do something to refresh the dog photo')
l.pack()
main.mainloop()

I have this code that gets a random dog photo and loads it in to a window, as well as a button. This works fine but the "Next Dog" button doesn't actually do anything, and the dog photo almost never matches up with the window. How could I add functionality to the button, and make the dog photo size consistent?



Solution 1:[1]

You can put the fetching of the dog image in a function and update the image of the label inside the function. Then assign this function to the command option of the button.

import tkinter, urllib.request, json, io
from PIL import Image, ImageTk

main = tkinter.Tk()
main.geometry('500x500+800+300')

# maximum size of image
W, H = 500, 460

# resize image but keeping the aspect ratio
def resize_image(img):
    ratio = min(W/img.width, H/img.height)
    return img.resize((int(img.width*ratio), int(img.height*ratio)), Image.ANTIALIAS)

def fetch_image():
    dogapi = urllib.request.urlopen(f'https://dog.ceo/api/breeds/image/random')
    dogjson = dogapi.read()
    dogdict = json.loads(dogjson)
    url = dogdict['message']
    m = urllib.request.urlopen(url)
    mpi = resize_image(Image.open(m))
    tkimg = ImageTk.PhotoImage(mpi)
    l.config(image=tkimg) # show the image
    l.image = tkimg # save a reference of the image to avoid garbage collection

# label to show the image
l = tkinter.Label(main, image=tkinter.PhotoImage(), width=W, height=H)
b = tkinter.Button(main, text='Next Dog', command=fetch_image)

l.pack()
b.pack()

fetch_image() # fetch first image
main.mainloop()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 acw1668