Tkinter界面调用API获取ISS位置并在Canvas显示时卡顿的解决求助
Tkinter界面调用API获取ISS位置并在Canvas显示时卡顿的解决求助
嗨,我完全懂你遇到的困扰——运行一段时间后UI就卡得动不了,对吧?咱们来拆解问题,一步步把它修好。
问题出在哪?
你的代码里,requests.get()是同步阻塞式的网络请求。每次调用这个方法时,Tkinter的主事件循环(就是管UI更新、用户点击这些交互的核心)会被彻底卡住,直到API返回数据才会继续干活。哪怕你只设了1秒间隔,只要网络偶尔延迟、或者API响应慢,这些阻塞累积起来,UI就会越来越卡,最后直接假死。
而且Tkinter有个严格规则:所有UI操作必须在主线程里执行,直接把同步请求塞在循环里,肯定会出问题。
解决方案:用线程分离网络操作
咱们把网络请求的活儿丢给单独的子线程干,让主线程专心处理UI,这样就不会阻塞界面了。注意!绝对不能在子线程里直接改Tkinter的UI元素,必须让主线程来做这件事。
这里用Python自带的threading模块实现,配合Tkinter的after()方法来安全更新UI。
修改后的完整代码如下:
from tkinter import * import requests import threading def fetch_iss_position(): # 子线程只负责网络请求,不碰UI try: # 给请求加超时,避免网络出问题时一直卡着 data = requests.get(url="http://api.open-notify.org/iss-now.json", timeout=5) data.raise_for_status() data = data.json() lat = data["iss_position"]["latitude"] long = data["iss_position"]["longitude"] # 让主线程来更新UI,这是线程安全的做法 window.after(0, update_ui, lat, long) except Exception as e: print(f"请求出错啦: {e}") # 不管成功失败,1秒后再启动下一次请求线程 window.after(1000, start_fetch_thread) def update_ui(lat, long): # 这个函数在主线程执行,专门负责更新Canvas文本 my_canvas.itemconfig(my_text, text=f"latitude = {lat}\nlongitude = {long}") def start_fetch_thread(): # 启动新的子线程处理请求 thread = threading.Thread(target=fetch_iss_position) thread.daemon = True # 设置守护线程,关闭窗口时线程自动退出,不残留后台进程 thread.start() window = Tk() window.title("ISS Position") window.config(padx=50, pady=50) window.minsize(300, 300) my_canvas = Canvas(height=300, width=300, highlightthickness=0) my_canvas.grid(column=0, row=0, padx=10, columnspan=2) my_text = my_canvas.create_text(150, 150, text="ISS POSITION", font=("arial", 16, "bold")) my_button = Button(text="Enter", command=start_fetch_thread, font=("arial", 16, "bold")) my_button.grid(column=0, row=1, columnspan=2) window.mainloop()
关键改动说明
- 把网络请求逻辑拆分到
fetch_iss_position(),交给子线程执行,彻底解放主线程 - 用
window.after(0, update_ui, lat, long)通知主线程更新UI,这是Tkinter官方推荐的线程安全更新方式 - 给
requests.get()加了timeout=5,防止网络异常时请求无限挂起 - 设置线程为守护线程,关闭窗口时自动结束,不会留下后台进程
额外小建议
- ISS的位置其实没那么快的更新频率,1秒一次请求有点频繁,改成5秒一次既减轻API服务器压力,也能减少本地线程开销
- 可以加个“停止”按钮,方便手动暂停追踪
这样修改后,你的UI应该就能一直流畅显示ISS的实时位置啦~
备注:内容来源于stack exchange,提问作者abhishek pandit
相关产品推荐
相关产品推荐

