Tkinter天气应用返回主界面后,明日预报仍显示旧数据问题
问题分析与解决方案
问题根源
- 全局变量引用失效:
tomorrow()函数始终引用程序启动时第一次调用opening()返回的city_entry,点击"Go back"后opening()重新创建的新输入框没有更新全局变量,导致再次点击明日预报时仍读取旧输入框内容。 - 界面重复创建:
goback()里调用opening()会重复生成顶部输入框、框架等元素,旧元素未被销毁导致界面层级混乱,新输入框也无法被tomorrow()识别。 - 局部变量覆盖全局:
tomorrow()内重新定义的second_frame局部变量覆盖了全局变量,导致后续操作无法正确关联主界面框架。
修复步骤
- 移除重复调用的
opening(),仅在程序启动时初始化一次界面。 - 让
tomorrow()直接读取当前活跃的city_entry内容,避免依赖全局变量的陈旧引用。 - 修改
goback()逻辑,不再重建整个界面,而是清空second_frame并恢复主界面的天气显示区域和明日预报按钮。 - 统一天气API调用逻辑,消除重复代码。
修复后的完整代码
import tkinter as tk import requests from PIL import ImageTk, Image window = tk.Tk() window.geometry('750x500') # 全局存储当前天气数据,避免重复请求API current_weather_data = None def format_response(weather, is_tomorrow=False): try: name = weather['city']['name'] # 当日取第0条数据,明日取第1条 data_index = 1 if is_tomorrow else 0 temperature = weather['list'][data_index]['main']['temp'] desc = weather['list'][data_index]['weather'][0]['description'] temp_feels = weather['list'][data_index]['main']['feels_like'] humidity = weather['list'][data_index]['main']['humidity'] wind_speed = weather['list'][data_index]['wind']['speed'] if is_tomorrow: final_str = f'City: {name} \nTemperature tomorrow: {temperature}°C --- will feel like: {temp_feels}°C \nConditions: {desc} \nHumidity: {humidity}% \nWind Speed: {wind_speed}m/s' else: final_str = f'City: {name} \nTemperature now: {temperature}°C --- feels like: {temp_feels}°C \nConditions: {desc} \nHumidity: {humidity}% \nWind Speed: {wind_speed}m/s' except: final_str = 'There was a problem retrieving that information' return final_str def get_weather(city): global current_weather_data weather_key = 'a9f553857df50650433c1577e3be6538' url = 'http://api.openweathermap.org/data/2.5/forecast' params = {'q': city, 'appid': weather_key, 'units': 'metric'} response = requests.get(url, params=params) current_weather_data = response.json() # 清空框架内容并显示当日天气 clear_second_frame() label_below['text'] = format_response(current_weather_data) # 添加明日预报按钮 temp_tmr = tk.Button(second_frame, font=('Bookman Old Style', 10), text="Tomorrow's Forecast", command=show_tomorrow_forecast) temp_tmr.place(relx=0.74, rely=0.88, relwidth=0.25, relheight=0.1) def clear_second_frame(): # 彻底销毁框架内所有控件,避免元素堆积 for widget in second_frame.winfo_children(): widget.destroy() def show_tomorrow_forecast(): if not current_weather_data: return clear_second_frame() # 显示明日天气信息 label_below2 = tk.Label(second_frame, font=('Bookman Old Style', 15), anchor="nw", justify="left", bd=4) label_below2.place(relwidth=1, relheight=1) label_below2['text'] = format_response(current_weather_data, is_tomorrow=True) # 添加返回主界面按钮 back_btn = tk.Button(second_frame, font=('Bookman Old Style', 10), text="Go back", command=go_back_to_main) back_btn.place(relx=0.01, rely=0.88, relwidth=0.12, relheight=0.1) def go_back_to_main(): # 返回主界面,恢复当日天气显示和明日预报按钮 if current_weather_data: clear_second_frame() label_below['text'] = format_response(current_weather_data) temp_tmr = tk.Button(second_frame, font=('Bookman Old Style', 10), text="Tomorrow's Forecast", command=show_tomorrow_forecast) temp_tmr.place(relx=0.74, rely=0.88, relwidth=0.25, relheight=0.1) def resize_image(event): new_width = event.width new_height = event.height image = copy_of_image.resize((new_width, new_height)) photo = ImageTk.PhotoImage(image) label.config(image=photo) label.image = photo # 初始化主界面 image = Image.open('img\\clouds.jpg') copy_of_image = image.copy() photo = ImageTk.PhotoImage(image) label = tk.Label(window, image=photo) label.bind('<Configure>', resize_image) label.pack(fill=tk.BOTH, expand=True) top_frame = tk.Frame(window, bg="#0cc961", bd=5) top_frame.place(relx=0.1, rely=0.05, relwidth=0.8, relheight=0.15) city_entry = tk.Entry(top_frame, font=('Bookman Old Style', 22)) city_entry.place(relwidth=0.65, relheight=1) # 绑定回车键触发查询,提升操作便捷性 city_entry.bind('<Return>', lambda e: get_weather(city_entry.get())) enter_button = tk.Button(top_frame, font=('Bookman Old Style', 18), text="Enter", command=lambda: get_weather(city_entry.get())) enter_button.place(relx=0.68, relwidth=0.31, relheight=1) second_frame = tk.Frame(window, bg="#0cc961", bd=5) second_frame.place(relx=0.1, rely=0.25, relwidth=0.8, relheight=0.7) label_below = tk.Label(second_frame, font=('Bookman Old Style', 15), anchor="nw", justify="left", bd=4) label_below.place(relwidth=1, relheight=1) window.mainloop()
关键改进点
- 用
current_weather_data全局变量存储天气数据,避免重复调用API。 - 统一
format_response函数,通过参数区分当日/明日数据,减少代码冗余。 - 改用
destroy()彻底销毁控件,避免界面元素堆积。 go_back_to_main()直接恢复主界面内容,确保city_entry始终是当前活跃的输入框。- 为输入框绑定回车键,符合用户操作习惯。
内容的提问来源于stack exchange,提问作者Josborne
相关产品推荐
相关产品推荐

