一个python小作业没想到引出这么多麻烦。要求是实现类似IPHONE手机得秒表计时,精确到小数点后两位(毫秒级),大概就是这种形式00:00.00,由分到毫秒。
看到有得人用wx.Timer设置定时器,但都是以秒为最小单位得,参数设置为毫秒时,如timer.Start(10),10ms时就会发现计时器跑一分钟比正常时间慢了6s左右。
又想到用time.time方法来,但是使用了while循环,页面刷新太快导致wx主界面卡死了,然后就一筹莫展。
最后用了线程,把time.time方法放到线程里执行,只传回参数来更新页面。这样初步是可以了,但是还有几个后续问题。
一个是还是会慢一些,大概会慢6s,但是可以通过修改代码解决,干脆不用tiem.time方法,只用while循环加sleep,每次时间加0.01s,但是sleep(0.009),少睡的0.001用于跑程序,因为1分钟大概误差6s,也就是6000ms,1分钟,程序更新时间的代码运行60000ms/10ms次,也就是6000次,6000次误差6000ms,每次误差1ms,也就是0.001s,所以sleep(0.01-0.001)。这样就弥补了误差,和正常时间无差。代码中有用来测试误差的备注代码,显示01:00.00时,时间戳结果为59.9820001125,这是不一定的,有时为59.99等,还是不错的精度(关于时间最关心的就是精度了,暂时最精确的时间是原子钟,为什么说暂时呢,因为原子钟过几十亿年也会产生1s误差,但是已经是人类能得到的最精确的时间了,机器会存在误差,关于时间精度的极限:没有最准,只有更准,这是我个人对于时间精度的理解)
第二个是使用wx.statictext控件来更新时间的话会导致有闪烁,具体原因不太清楚,可能是控件界面更新太快了,试了下几种解决方法后干脆改成led显示,led数字也是wx自带的,解决了这个问题。
代码中有一些按钮的转换逻辑,以及添加了背景图片,以及利用sqlite3保存了数据,判断了计时上限,判断了保存状态等等等这些细节,可以自己看情况修改。
下面直接上代码,基本都有注释,但是使用线程传递数据这点需要自己好好理解。
下面展示完整代码
。
https://blog.csdn.net/weixin_43141119/article/details/105239008 这个是不使用线程的其他做法 欢迎移步
(关于时间上的区别 我的做法显示的是连续的时间 但是会损失了精度 这个做法时间精确 但是显示的却是不连续的时间)
#coding = utf-8
import wx
import wx.gizmos as gizmos
import time
import threading
import os
import sqlite3
#返回一个唯一的事件类型ID赋值给EVT_RESULT_ID
EVT_RESULT_ID = wx.NewId()
#自定义一个事件类型,用于线程向主界面传递数据
class ResultEvent(wx.PyEvent):
def __init__(self, data):
wx.PyEvent.__init__(self)
self.SetEventType(EVT_RESULT_ID)
self.data = data
#自定义事件绑定函数,类似wx自带的wx.EVT_BUTTON
def EVT_RESULT(win, func):
win.Connect(-1, -1, EVT_RESULT_ID, func)
#定义线程类
class WorkerThread(threading.Thread):
def __init__(self, notify_window):
threading.Thread.__init__(self)
self._notify_window = notify_window
self.resume_reset = 0#用于区分继续和重启线程
self.__flag = threading.Event()#控制线程暂停或启动
self.start()
#启动线程,循环计时
def run(self):
t = 0
#测试一分钟误差代码
#starttime = time.time()
while True:
t += 10
mm = int((t/1000) / 60)
ss = int((t/1000) % 60)
xx = int((t%1000) / 10)
text_time = "{:02d}:{:02d}.{:02d}".format(mm,ss,xx)
#if mm == 01 and ss == 00 and xx == 00:
#测试一分钟误差代码
#print (time.time() - starttime)
#self.__flag.clear()
if mm == 59 and ss == 59 and xx == 99:
self.__flag.clear()
#向MainFrame传递时间
wx.PostEvent(self._notify_window, ResultEvent(text_time))
time.sleep(0.009)
#重置秒表
if self.resume_reset == 1:
wx.PostEvent(self._notify_window, ResultEvent("00:00.00"))
t = 0.0
self