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的更新未正确关联到已有标签,且局部变量作用域限制了修改效果。
修改步骤
提前创建全局
image_label
在初始化标签的区域添加全局的图标标签,避免每次更新都新建组件:image_label = CTkLabel(app, image=c_img, text="")调整
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 # 强制保留引用,避免图标被回收- 用
调整组件布局顺序
在初始化阶段就将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
相关产品推荐
相关产品推荐

