Python 之后,时钟倒转后仍能生存
我注意到,在我的Tkinter版本中,after()调用无法在系统时钟倒转后继续执行 如果调用了after(x,func),并且系统时钟被倒带,则只有在时钟返回到倒带+x毫秒之前的时间后,才会调用func 我假设这是因为Tkinter使用系统时钟而不是“time.clock”(程序运行的时间) 我只在windows上测试了它,可能是因为我有一个Tkinter的旧版本。 我希望我的应用程序在与网络同步时钟的计算机上运行 有人有简单的解决方案吗?解释 正如您所怀疑的,当您使用Python 之后,时钟倒转后仍能生存,python,windows,tkinter,Python,Windows,Tkinter,我注意到,在我的Tkinter版本中,after()调用无法在系统时钟倒转后继续执行 如果调用了after(x,func),并且系统时钟被倒带,则只有在时钟返回到倒带+x毫秒之前的时间后,才会调用func 我假设这是因为Tkinter使用系统时钟而不是“time.clock”(程序运行的时间) 我只在windows上测试了它,可能是因为我有一个Tkinter的旧版本。 我希望我的应用程序在与网络同步时钟的计算机上运行 有人有简单的解决方案吗?解释 正如您所怀疑的,当您使用.after()时,tk
.after()
时,tkinter正在安排事件在当前时间+延迟时间发生。这意味着,如果这些事件之间的系统时间发生变化,它将破坏计划的事件
这是基于这样一个事实,即只需在tcl(tkinter正在与之通信的底层系统)的之后调用。告诉我们:
after使用系统时间确定何时执行计划事件。这意味着,除0后和空闲后外,它可以被系统时间的变化所破坏
现在请注意,空闲后的和0后的都不受系统时钟耦合的影响,但这些可能不是很好的替代品
在0之后
这会安排脚本立即执行。这对于获得尽可能紧密的活动非常有用。警告:这会将计划的事件放在队列的前面,因此,以这种方式重新计划自身的命令可以锁定队列。
因此,在0之后使用将不是最佳选择,因为它位于事件队列的前面,这意味着不会发生其他任何事情
怠速后
这也是同样的豁免,但可能也不是最好的
下次进入事件循环且没有要处理的事件时,脚本将只运行一次
因此,脚本将在系统下一次空闲时运行。您可以将after x
与after idle
一起使用,这将等待事件清除且系统处于空闲状态,然后在运行该命令之前等待x
毫秒,但我怀疑您也不想这样做
Tl;dr
那么对于你的最后一个问题,如果时钟可以倒转,你能做什么呢?特金特人:不多。除非您捕捉到相反的情况并重置after()
事件,或者基于time.process\u time()
(以前是time.clock()
)编写自己的事件调度程序,否则我看不到让.after()
执行不同操作的方法。不幸的是,Tkinter和Tcl解释器都没有解决问题的简单方法。after(ms,func)
方法基于同名的Tcl命令,该命令根据当前系统时间加上作为参数传递的毫秒数创建一个内部计时器
如果您感兴趣,可以直接从以下网站查看:
考虑到这一限制,我会选择纯Python方法,比如使用:
它还具有在单独线程上运行的优势,不仅可以防止在计时器间隔期间阻塞GUI,还可以防止在执行回调函数时阻塞GUI。我找到了一种适用于我的程序的解决方案,但它不是通用的。我的程序有几个线程,所以其他线程中的一个可以执行:app.event_generate(“,when='tail'),然后我根本不需要调用“after”…你能给出一个小的代码示例来说明你在说什么吗。我知道你说过你有一个适合你的解决方案,但也许有更好的/标准的方法来解决这个问题。
Tcl_GetTime(&wakeup);
wakeup.sec += (long)(ms / 1000);
wakeup.usec += ((long)(ms % 1000)) * 1000;
if (wakeup.usec > 1000000) {
wakeup.sec++;
wakeup.usec -= 1000000;
}
afterPtr->token = TclCreateAbsoluteTimerHandler(&wakeup,
AfterProc, afterPtr);
import time
import threading
import tkinter as tk
root = tk.Tk()
def say_hi():
print(time.perf_counter(), "-", "Hi after 30sec!")
root.destroy()
print(time.perf_counter(), "-", "Waiting 30sec")
threading.Timer(30, say_hi).start()
root.mainloop()