You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Custom Tkinter天气应用:切换城市时天气图标无法更新求助

问题:Custom Tkinter天气应用切换城市时天气图标无法正常更新

我用Custom Tkinter结合OpenWeather API开发简易天气应用,现在遇到的问题是:用户从指定城市列表输入另一城市时,天气图标无法正常更新。尝试过更新c_img的light_image,但只能成功一次,还会重复显示图标。应用还在开发阶段,代码比较杂乱,见谅。

原代码

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()

尝试过的方法

我曾尝试通过以下方式更新图标,但仅能成功更新一次,且图标会重复显示在窗口中:

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

###Code###

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

解决方案

问题根源有两个:每次调用update_weather都新建image_label并执行pack(),导致图标重复渲染;另外c_img的更新未正确关联到已有标签,且局部变量作用域限制了修改效果。

修改步骤

  1. 提前创建全局image_label
    在初始化标签的区域添加全局的图标标签,避免每次更新都新建组件:

    image_label = CTkLabel(app, image=c_img, text="")
    
  2. 调整update_weather函数内的图标更新逻辑

    • 用global声明需要修改的全局变量,确保作用域正确
    • 重新创建CTkImage实例(Custom Tkinter中直接修改CTkImage的属性可靠性较低)
    • 调用image_label.configure()更新已有标签的图标,同时保留对新图标的引用防止被垃圾回收

    修改后的函数关键片段:

    def update_weather(event):
        global c_img, filename1
        filename1 = 'cloudy.jpg'
        ecity = name_entry.get()
    
        # ... 保留原有的API请求和天气数据处理代码 ...
    
        # 天气图标判断逻辑保持不变 ...
    
        # 更新图标
        c_img = CTkImage(light_image=Image.open(filename1), size=(100, 100))
        image_label.configure(image=c_img)
        image_label.image = c_img  # 强制保留引用,避免图标被回收
    
  3. 调整组件布局顺序
    在初始化阶段就将image_label加入窗口布局,不要在函数内执行pack():

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

完整修改后的代码

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))
# 提前创建全局图标标签
image_label = CTkLabel(app, image=c_img, text="")
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):
    global c_img, filename1
    filename1 = 'cloudy.jpg'
    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'

    # 更新图标:重新创建CTkImage并更新已有标签
    c_img = CTkImage(light_image=Image.open(filename1), size=(100, 100))
    image_label.configure(image=c_img)
    image_label.image = c_img  # 保留引用防止图标被回收

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

update_weather(True)
# 按顺序布局组件
image_label.pack()
msg_label.pack()
temp_label.pack()
condition_label.pack()
wind_label.pack()
alert_label.pack()
name_entry.pack()

app.mainloop()

内容的提问来源于stack exchange,提问作者primeCEOstack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:25:54