如何用tkinter.after()多次调用实现PLC脚本的时序执行逻辑?
Tkinter 时序控制问题解答
先给你明确两个核心结论:
- 所有
tkinter.after()的计时都是从你调用它的那一刻起独立算时间,不是等前一个after任务跑完才开始计时。 - 像
cycleStartWidget.grid()这种普通同步代码,会立刻执行,根本不会等after()里的延迟任务。
你给的代码里的问题
看你写的这段代码:
logStartWidget.grid() widget.after(3000, lambda: plc.write((onTag,1))) cycleStartWidget.grid() # 这行在logStartWidget.grid()之后马上就跑,不会等那3秒 cycleRunningWidget.grid() # 这个after的计时和前一个同时开始,不是等plc.write完再算时间 widget.after(3000+cycle_runtime*1000, lambda: plc.write((onTag, 0)))
这里的问题很明显:
- 循环开始的控件会直接显示,不符合你终端脚本里“等3秒再提示循环启动”的逻辑
- 第二个
after()的计时和第一个同时启动,不是等PLC写入启动信号后再等cycle_runtime,时序完全不对
正确的实现方式
要完全复刻终端脚本的流程,得把后续步骤嵌套到前一个after()的回调里,形成链式执行:
def start_logging(): logStartWidget.grid() # 启动日志子进程 logger = subprocess.Popen(*start logging args*) # 3秒后启动循环流程 widget.after(3000, start_cycle, logger) def start_cycle(logger): plc.write((onTag, 1)) cycleStartWidget.grid() cycleRunningWidget.grid() # 等cycle_runtime秒后结束循环 widget.after(int(cycle_runtime*1000), finish_cycle, logger) def finish_cycle(logger): plc.write((onTag, 0)) cycleRunningWidget.grid_remove() print("Cycle finished") logger.stop() # 触发整个流程 start_logging()
这个逻辑和你终端脚本完全一致:
- 先显示日志启动控件,启动日志进程
- 等3秒,给PLC发启动信号,显示循环开始/运行的控件
- 等cycle_runtime秒,给PLC发停止信号,结束日志
额外提醒
- 要是硬要用连续的
after(),你得精确算每个任务的总延迟(比如第一个3000,第二个3000+cycle_runtime*1000),但这种方式很脆——如果PLC写入耗时,整个时序就乱了。嵌套调用的方式更靠谱,因为它是在前一个任务做完之后才开始算下一个的时间。 - 如果你的PLC操作耗时比较久,最好放到子线程里跑,别卡住GUI。
内容的提问来源于stack exchange,提问作者narab
相关产品推荐
相关产品推荐

