试图理解为什么我的秒表代码什么都不做 (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。你可以看到后者比前者涉及更多。