Search code examples
pythontkintercustomtkinter

Image update in Custom Tkinter


I'm making a simple weather app in Custom Tkinter usimg OpenWeather's API, and I'm having trouble updating the weather icon when the user enters another city from the list. I'm still working on the app, excuse the messy code.

import requests
from customtkinter import *
from PIL import Image


app = CTk()
app.title('Turtle')
app.geometry('1000x500')





c_img = CTkImage(light_image=Image.open('cloudy.jpg'),size=(100, 100))
msg_label = CTkLabel(app, text="", text_color='Blue', font=('Arial', 25, 'bold'))
temp_label = CTkLabel(app, text="", text_color='Blue', font=('Arial', 25, 'bold'))
condition_label = CTkLabel(app, text="", text_color='Blue', font=('Arial', 25, 'bold'))
wind_label = CTkLabel(app, text="", text_color='Blue', font=('Arial', 25, 'bold'))
alert_label = CTkLabel(app, text="", text_color='Blue', font=('Arial', 25, 'bold'))



filename1 = "cloudy.jpg"




name_entry = CTkEntry(app, font=('Arial', 25, 'bold'), corner_radius=32)

ecity = ""




def update_weather(event):
 
 filename1 = 'cloudy.jpg'
 ecity = ""
 ecity = name_entry.get()


 #Fetch weather information from OpenWeatherMap API
 api = '928c56960d62b32ac062752c50a07679'  

 cityid = '6094817'
 
 if ecity.lower() == "mecca" :
        cityid = '104515'
 elif ecity.lower() == "medina":
        cityid = '109223'
 elif ecity.lower() == "tokyo":
        cityid = '1850147'
 elif ecity.lower() == "dubai":
        cityid = '292224'
 elif ecity.lower() == "new york":
        cityid = '5128581'
 elif ecity.lower() == "paris":
        cityid = '6455259'
 elif ecity.lower() == 'london':
        cityid = '1006984'
 elif ecity.lower() == "shanghai":
        cityid = '1796236'
 elif ecity.lower() == 'ottawa':
        cityid = '6094817'  #Ottawa city ID

 apiurl = f'''http://api.openweathermap.org/data/2.5/weather?id={cityid}&appid={api}&units=metric'''
 response = requests.get(apiurl)

 
 if response.status_code == 200:
     data = response.json()
     cityname = data['name']
     temperature = data['main']['temp']
     condition = data['weather'][0]['description']
     windspeed = data['wind']['speed']
     alert = data.get('alerts')
    
    
     print(f"Weather for {cityname}")
     print("Temperature:", temperature)
     print("Wind speed", windspeed)
     print("Condition:", condition)
     print(data)
    
     msg_label.configure(text=f"Weather for {cityname}: ", font=('Arial', 20, 'bold'))
     temp_label.configure(text=f"Temperature: {temperature}°C", font=('Arial', 20, 'bold'))
     condition_label.configure(text=f"Condition: {condition}", font=('Arial', 20, 'bold'))
     wind_label.configure(text=f"Wind speed: {windspeed}m/s", font=('Arial', 20, 'bold'))
     alert_label.configure(text=f"Weather alerts: {alert}", font=('Arial', 20, 'bold'))
    
    
 else:
     print("Failed to fetch weather information.")

 if 'rain' in condition.lower():
      filename1 = 'rainy.jpeg'
 elif 'light rain' in condition.lower():
      filename1 = 'rainy.jpeg'
 elif 'overcast clouds' in condition.lower():
         filename1 = 'cloudy.jpg'
 elif 'broken clouds' in condition.lower():
      filename1 = 'cloudy.jpg'
 elif 'sunny' in condition.lower():
         filename1 = 'sunny.png'
 elif 'sun' in condition.lower():
        filename1 = 'sunny.png'
 elif 'thunder storm' in condition.lower():
      filename1 = 'thunderstorm.png'
 elif 'snowy' in condition.lower():
      filename1 = 'snowy.png'
 elif 'snow' in condition.lower():
      filename1 = 'snowy.png'






 image_label = CTkLabel(app, image=c_img, text="")
 image_label.pack()

name_entry.bind('<Return>', lambda event: update_weather(event))



update_weather(True)
msg_label.pack()
temp_label.pack()
condition_label.pack()
wind_label.pack()
alert_label.pack()
name_entry.pack()

app.mainloop()


I tried using a CTkLabel instead:

c_img = CTkImage(light_image=Image.open('cloudy.jpg'),size=(100, 100))

###Code###

c_img.configure(light_image = Image.open(filename1))

It updated, but only once, and printed out the image to the window.


Solution

  • You should create image_label once instead of creating new one whenever update_weather() is executed. And you need to update c_img inside the function:

    ...
    
    c_img = CTkImage(light_image=Image.open('cloudy.jpg'),size=(100, 100))
    # create image_label here
    image_label = CTkLabel(app, text="", image=c_img)
    ...
    
    def update_weather(event):
        ...
        # update image of c_img
        c_img.configure(light_image=Image.open(filename1))
        # don't create new label
        #image_label = CTkLabel(app, image=c_img, text="")
        #image_label.pack()
    
    ...
    
    update_weather(True)
    image_label.pack()
    ...