试图理解为什么我的秒表代码什么都不做 (Python)
Trying to understand why my stopwatch code is doing nothing (Python)
我正在尝试编写 python 代码,使用 tkinter 在输入框中显示秒表。
我的想法是使用递归函数使用 time.sleep(1) 每秒给盒子加 1。
我很困惑 - 当我按下任一按钮时没有任何反应,而且我没有收到任何错误代码,所以我不知道为什么它不起作用。
我唯一一次得到盒子里的东西是在按停止后,它总是“00:00:00”。
from tkinter import *
import time
root = Tk()
root.title("Stopwatch")
#box to display stopwatch
box = Entry(root, width = 20, borderwidth = 5)
box.grid(row = 0, column = 0)
#displays stopwatch in the box
def show_timer():
global hrs, mins, secs, timer
timer = str(hrs).zfill(2) + ":" + str(mins).zfill(2) + ":" + str(secs).zfill(2)
box.delete(0, END)
box.insert(0, timer)
#check = 1 allows the stopwatch to run
def set_check(i):
global check
check = i
return check
#actual function for stopwatch
def stopwatch():
global check, hrs, mins, secs
if check == 1:
time.sleep(1)
if int(secs) < 59:
secs += 1
return secs
elif mins < 59:
mins += 1
secs = 0
return mins, secs
else:
hrs += 1
mins = 0
secs = 0
return hrs, mins, secs
show_timer()
stopwatch()
else:
show_timer()
def start():
global hrs, mins, secs
hrs, mins, secs = 0, 0, 0
return hrs, mins, secs
show_timer()
set_check(1)
stopwatch()
def stop():
set_check(0)
stopwatch()
start_button = Button(root, text = "Start", command = start)
stop_button = Button(root, text = "Stop", command = stop)
start_button.grid(row = 1, column = 0)
stop_button.grid(row = 2, column = 0)
root.mainloop()
您的代码有几个问题。
- 从回调函数调用
time.sleep()
会中断 tkinter
事件循环,使 GUI 无响应。
from tkinter import *
不推荐。为避免名称空间污染,请使用例如import tkinter as tk
.
- 你从
start
return
(= 退出函数)而不做任何事情。
- 您的函数不需要
return
语句;您似乎没有使用返回值。
stopwatch
中的内部if
语句的三个分支都调用了return
,所以stopwatch
永远不能被递归调用。这可能不是您想要的。
- 这是一件好事,因为来自回调的递归调用也会中断事件循环。
- 只有当你想修改变量时才需要使用
global
。所以例如show_timer
不需要 global
。 (顺便说一句,您可以使用 global
.)
- 您指定为
global
的名称在全局上下文中不存在。
一般来说,事件驱动程序不会运行 有严格的时间表。您可以使用 root.after()
让它在特定时间后执行回调,但不能保证这个时间是准确的。
所以我建议是:
- 保存启动秒表的时间。
- 使用每秒 运行 次的
after
回调。
- 在该回调中,获取当前时间并从中减去开始时间。显示差异。
- 注意在
after
回调结束时,必须重新注册才能保持运行ning。 (除非按下停止按钮。
在我的 tkinter 程序中,我喜欢将所有状态保持在一个 types.SimpleNamespace
中,以明确这是程序状态。
这是一个有此更改的工作版本:
import time
import types
import tkinter as tk
def start():
state.starttime = time.time()
state.run = True
display()
root.after(1000, update)
def stop():
state.run = False
state.starttime = None
box.delete(0, tk.END)
def update():
if state.run:
display()
root.after(1000, update)
def display():
difference = int(time.time() - state.starttime)
minutes, seconds = divmod(difference, 60)
hours, minutes = divmod(minutes, 60)
display = "{:02d}:{:02d}:{:02d}".format(hours, minutes, seconds)
box.delete(0, tk.END)
box.insert(0, display)
if __name__ == '__main__':
# Create program state
state = types.SimpleNamespace()
state.starttime = None
state.run = False
# Create widgets.
root = tk.Tk()
root.title("Stopwatch")
root.attributes('-type', 'dialog')
# box to display stopwatch
box = tk.Entry(root, width=20, borderwidth=5)
box.grid(row=0, column=0)
start_button = tk.Button(root, text="Start", command=start)
stop_button = tk.Button(root, text="Stop", command=stop)
start_button.grid(row=1, column=0)
stop_button.grid(row=2, column=0)
# Run the GUI
root.mainloop()
编辑
如果您是 Python 的新手,从可以简单地从命令行调用的脚本开始可能是明智的(cmd.exe
on ms-windows)。这些通常更容易读写,因为它们具有大部分线性控制流。在我的网站上,我有一个关于两个等效程序的 article,一个是简单的命令行脚本,另一个是 tkinter
GUI。你可以看到后者比前者涉及更多。
我正在尝试编写 python 代码,使用 tkinter 在输入框中显示秒表。
我的想法是使用递归函数使用 time.sleep(1) 每秒给盒子加 1。
我很困惑 - 当我按下任一按钮时没有任何反应,而且我没有收到任何错误代码,所以我不知道为什么它不起作用。
我唯一一次得到盒子里的东西是在按停止后,它总是“00:00:00”。
from tkinter import *
import time
root = Tk()
root.title("Stopwatch")
#box to display stopwatch
box = Entry(root, width = 20, borderwidth = 5)
box.grid(row = 0, column = 0)
#displays stopwatch in the box
def show_timer():
global hrs, mins, secs, timer
timer = str(hrs).zfill(2) + ":" + str(mins).zfill(2) + ":" + str(secs).zfill(2)
box.delete(0, END)
box.insert(0, timer)
#check = 1 allows the stopwatch to run
def set_check(i):
global check
check = i
return check
#actual function for stopwatch
def stopwatch():
global check, hrs, mins, secs
if check == 1:
time.sleep(1)
if int(secs) < 59:
secs += 1
return secs
elif mins < 59:
mins += 1
secs = 0
return mins, secs
else:
hrs += 1
mins = 0
secs = 0
return hrs, mins, secs
show_timer()
stopwatch()
else:
show_timer()
def start():
global hrs, mins, secs
hrs, mins, secs = 0, 0, 0
return hrs, mins, secs
show_timer()
set_check(1)
stopwatch()
def stop():
set_check(0)
stopwatch()
start_button = Button(root, text = "Start", command = start)
stop_button = Button(root, text = "Stop", command = stop)
start_button.grid(row = 1, column = 0)
stop_button.grid(row = 2, column = 0)
root.mainloop()
您的代码有几个问题。
- 从回调函数调用
time.sleep()
会中断tkinter
事件循环,使 GUI 无响应。 from tkinter import *
不推荐。为避免名称空间污染,请使用例如import tkinter as tk
.- 你从
start
return
(= 退出函数)而不做任何事情。 - 您的函数不需要
return
语句;您似乎没有使用返回值。 stopwatch
中的内部if
语句的三个分支都调用了return
,所以stopwatch
永远不能被递归调用。这可能不是您想要的。- 这是一件好事,因为来自回调的递归调用也会中断事件循环。
- 只有当你想修改变量时才需要使用
global
。所以例如show_timer
不需要global
。 (顺便说一句,您可以使用global
.) - 您指定为
global
的名称在全局上下文中不存在。
一般来说,事件驱动程序不会运行 有严格的时间表。您可以使用 root.after()
让它在特定时间后执行回调,但不能保证这个时间是准确的。
所以我建议是:
- 保存启动秒表的时间。
- 使用每秒 运行 次的
after
回调。 - 在该回调中,获取当前时间并从中减去开始时间。显示差异。
- 注意在
after
回调结束时,必须重新注册才能保持运行ning。 (除非按下停止按钮。
在我的 tkinter 程序中,我喜欢将所有状态保持在一个 types.SimpleNamespace
中,以明确这是程序状态。
这是一个有此更改的工作版本:
import time
import types
import tkinter as tk
def start():
state.starttime = time.time()
state.run = True
display()
root.after(1000, update)
def stop():
state.run = False
state.starttime = None
box.delete(0, tk.END)
def update():
if state.run:
display()
root.after(1000, update)
def display():
difference = int(time.time() - state.starttime)
minutes, seconds = divmod(difference, 60)
hours, minutes = divmod(minutes, 60)
display = "{:02d}:{:02d}:{:02d}".format(hours, minutes, seconds)
box.delete(0, tk.END)
box.insert(0, display)
if __name__ == '__main__':
# Create program state
state = types.SimpleNamespace()
state.starttime = None
state.run = False
# Create widgets.
root = tk.Tk()
root.title("Stopwatch")
root.attributes('-type', 'dialog')
# box to display stopwatch
box = tk.Entry(root, width=20, borderwidth=5)
box.grid(row=0, column=0)
start_button = tk.Button(root, text="Start", command=start)
stop_button = tk.Button(root, text="Stop", command=stop)
start_button.grid(row=1, column=0)
stop_button.grid(row=2, column=0)
# Run the GUI
root.mainloop()
编辑
如果您是 Python 的新手,从可以简单地从命令行调用的脚本开始可能是明智的(cmd.exe
on ms-windows)。这些通常更容易读写,因为它们具有大部分线性控制流。在我的网站上,我有一个关于两个等效程序的 article,一个是简单的命令行脚本,另一个是 tkinter
GUI。你可以看到后者比前者涉及更多。