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

如何让Tkinter程序等待上一行代码执行完成后再执行后续逻辑?

问题根因

Tkinter基于单线程事件循环运行,该问题由两个核心特性导致:

  • window.after()为异步非阻塞方法:调用后仅将待执行回调注册到事件队列,立刻返回执行后续代码,不会等待回调执行完成。原有for循环会在几毫秒内完成3次请求,连续注册3个1秒后恢复背景的回调,所有UI修改被挤压在事件队列中,视觉上仅生效一次。
  • requests.get()为同步阻塞方法:执行时会卡住Tkinter事件循环,修改的标签文本、背景色无法及时渲染,直到请求完成才会更新,因此看不到中间状态变化。
修改方案

把同步循环逻辑改成异步递归调度,每次请求、状态展示完整结束后,再触发下一次请求,同时将请求逻辑放到子线程避免阻塞UI:

# import gpiozero
# import picamera
import json
import requests
import tkinter as tk
import threading # 新增导入,用于异步执行请求

with open("config.json") as file:
    config = json.load(file)

ENDPOINT = config["ENDPOINT"]
USUARIO = config["USUARIO"]
ESTACION = config["ESTACION"]
TIEMPO_ESPERA = config["TIEMPO_ESPERA"]
PIN_RELE = config["PIN_RELE"]
PATH_SALIDA = ENDPOINT + "Salida.getTicket/" + ESTACION + "/" + USUARIO + "/"
barcode = ""

# RELAY = gpiozero.OutputDevice(PIN_RELE, active_high=True, initial_value=False)
# CAMERA = picamera.PiCamera()

def check_scan_barcode(event=None):
    info_label.config(text = "Wait...")
    global barcode # 声明全局变量存储扫码结果
    barcode = barcode_entry.get()
    barcode_entry.delete(0, "end")
    # 启动异步请求,计数器从0开始
    run_check(0)

# 新增异步校验递归函数
def run_check(count):
    # 3次请求都完成就恢复初始状态
    if count >= 3:
        info_label.config(text = "Scan barcode")
        normal()
        return
    
    # 请求放子线程执行,避免阻塞UI
    def do_request():
        response = get_request(ENDPOINT + barcode)
        # UI修改必须放回主线程执行,用after调度
        if response["data"] == "True":
            window.after(0, success)
            window.after(0, open_barrier, barcode)
        else:
            window.after(0, error)
        # 1秒后(背景展示完成)触发下一次校验
        window.after(1000, run_check, count + 1)
    
    threading.Thread(target=do_request, daemon=True).start()

def get_request(url):
    try:
        response = requests.get(url, timeout=5) # 加超时避免卡住
        response.raise_for_status()
        return response.json()
    except:
        # 请求异常统一返回错误
        return {"data": "False"}

def normal():
    window.configure(bg="white")
    info_label.configure(bg="white")

def success():
    window.configure(bg="green")
    info_label.configure(bg="green")
    
def error():
    window.configure(bg="red")
    info_label.configure(bg="red")

def open_barrier(barcode):
    # CAMERA.capture(f"/home/pi/Pictures{barcode}.jpg")
    # RELAY.on()
    # window.after(TIEMPO_ESPERA, RELAY.off)
    pass

window = tk.Tk()
    
# window.attributes('-fullscreen', True)

info_label = tk.Label(window, text= "Scan barcode.", font=("Arial", 40))
info_label.pack()
barcode_entry = tk.Entry(window, width=50)
barcode_entry.bind('<Return>', check_scan_barcode)
barcode_entry.pack(expand=True)
barcode_entry.focus()

window.mainloop()
逻辑说明
  • 用run_check递归函数替代原来的for循环,每次请求完成、状态展示1秒后才会触发下一次请求,保证执行顺序严格按预期走
  • 所有网络请求放在子线程执行,不会卡住UI渲染,修改UI的操作统一用window.after(0, 回调)调度回主线程执行,符合Tkinter的线程安全要求
  • 去掉了success和error里的after调度,统一在递归逻辑里控制下一次执行的时机,避免多个回调冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 13:45:03