我做了一个倒数计时器,每当我按下键盘上的空格键就开始,但问题是,在计时器结束之前,我不能在程序上做任何事情。当第二次按空格键时,我想让它暂停。
我制作的倒计时计时器在waits循环中工作,当计时器达到0时结束,所以程序在执行任何其他操作之前一直等到循环结束,即使我想停止计时器,我也不能在它运行时停止它。
这是密码
from tkinter import *
from tkinter import ttk
import tkinter as tk
from PIL import ImageTk, Image
def StartTimer():
if (root.turn % 2) == 0: #Turn to white
root.number = '1'
root.color = 'white'
else: #Turn to black
root.number = '2'
root.color = 'black'
doTimer()
def doTimer():
root.time = root.minute *60 + root.second
root.turn = root.turn+1
number = root.number
root.rndsquare1.configure(image=root.green)
root.timer1.configure(bg='#1C953D')
root.white.configure(bg='#1C953D')
r=0
while r < root.time:
root.update_idletasks()
root.after(1000)
root.second = root.second - 1
if root.second == -1:
root.minute = root.minute -1
root.second = 59
root.time1 = ''
if len(str(root.minute)) == 1:
root.time1 = '0' + str(root.minute)
else:
root.time1 = str(root.minute)
if len(str(root.second)) == 1:
root.time1 = root.time1 + ':' + '0' + str(root.second)
else:
root.time1 = root.time1 + ':' + str(root.second)
root.timer1.configure(text=root.time1)
r=r+1
root.timer1.configure(bg='#454545')
root.white.configure(bg='#454545')
root.rndsquare1.configure(image=root.grey)
class root(Tk):
def __init__(self):
super(root, self).__init__()
self.title("Chess Clock")
self.minsize(1539,600)
self.windowBG = '#313131'
self.state('zoomed')
self.configure(bg=self.windowBG)
self.CreateWindow()
def CreateWindow(self):
self.grey = ImageTk.PhotoImage(Image.open(r"D:\Users\Jean Paul\OneDrive\Programming\Programs\Prog 6 - Chess Clock\bg square grey.png"))
self.green = ImageTk.PhotoImage(Image.open(r"D:\Users\Jean Paul\OneDrive\Programming\Programs\Prog 6 - Chess Clock\bg square green.png"))
self.turn=0
self.rndsquare1 = Label(self, image=self.grey, borderwidth=0)
self.rndsquare1.place(x=65, y=120)
self.rndsquare2 = Label(self, image=self.grey, borderwidth=0)
self.rndsquare2.place(x=809, y=120)
self.bind('<space>',lambda event:StartTimer())
self.createTimers()
def createTimers(self):
self.minute = 1
self.second = 5
self.time1 = ''
if len(str(self.minute)) == 1:
self.time1 = '0' + str(self.minute)
else:
self.time1 = str(self.minute)
if len(str(self.second)) == 1:
self.time1 = self.time1 + ':' + '0' + str(self.second)
else:
self.time1 = self.time1 + ':' + str(self.second)
self.time2 = ''
if len(str(self.minute)) == 1:
self.time2 = '0' + str(self.minute)
else:
self.time2 = str(self.minute)
if len(str(self.second)) == 1:
self.time2 = self.time2 + ':' + '0' + str(self.second)
else:
self.time2 = self.time2 + ':' + str(self.second)
self.timer1 = Label(self, text=self.time1, bg='#454545', fg='white', font ="Gadugi 40 bold")
self.timer1.place(x=330, y=420)
self.timer2 = Label(self, text=self.time2, bg='#454545', fg='white', font ="Gadugi 40 bold")
self.timer2.place(x=1080, y=420)
self.white = Label(self, text='White', bg='#454545', fg='white', font ="Gadugi 40 bold")
self.white.place(x=325, y=160)
self.black = Label(self, text='Black', bg='#454545', fg='white', font ="Gadugi 40 bold")
self.black.place(x=1075, y=160)
root=root()
root.mainloop()
D:\Users\Jean Paul\OneDrive\Programming\Programs\Prog 6 - Chess Clock\bg square grey.png
D:\Users\Jean Paul\OneDrive\Programming\Programs\Prog 6 - Chess Clock\bg square green.png
发布于 2022-05-21 11:29:31
您可以通过大量重构代码来解决这个问题。您可以添加2个时钟到您的小部件,每个时钟跟踪多少是花在自己身上。空格监听器只需切换当前正在使用的时钟。通过每200毫秒左右设置一个定时do_clock_logic
,它将检查当前时钟是否已设置,如果时间已到,则切换到另一个时钟。在任何情况下,它都会触发clocks ()方法来更新其内部状态,这些状态也会处理ui更新。
这样就不存在“阻塞”而循环,所有的定时操作都由tk处理:
from tkinter import Tk, Label
import tkinter as tk
from PIL import ImageTk, Image
from datetime import datetime, timedelta
class clock():
"""A single clock that handles updating/timekeeping itself. It uses
the both class-level memebrs as active/inactive image and has
references provided to place the image and the timing text."""
active_img = None
deactive_img = None
@staticmethod
def format_time(delta, ms = False):
"""Returns a formatted strng for a timedelta instance,
optionally with milliseconds"""
return f"{delta.seconds//60:02}:{delta.seconds%60:02}" + (
f".{(delta.microseconds // 1000):04}" if ms else "")
def __init__(self, minutes, seconds, bg_lbl, text_lbl):
"""Set the clocks max duration providing 'minutes' and 'seconds'.
Provide tk-labels with a background image 'bg_lbl' and
'text_lbl' for the time display."""
self.max_duration = timedelta(seconds=seconds+minutes*60)
# UI
self.bg_lbl = bg_lbl,
self.text_lbl = text_lbl
# reset to inactive image and no text
self.bg_lbl[0].config(image = clock.deactive_img)
self.text_lbl.config(text = "")
# internal time keeping of total spent time1
self.total = timedelta() # 0 delta at start
def update_lbl(self, spent):
# update the image if needed
self.bg_lbl[0].config(image = clock.active_img if self.started is not None else clock.deactive_img)
# update labels - if not active - show with milliseconds
if self.started is not None:
self.text_lbl.config( text = clock.format_time(self.max_duration - spent))
else:
self.text_lbl.config(text = f"Total:\n{clock.format_time(self.total, True)}")
def start_clock(self):
# starts the clock
self.started = datetime.now()
self.update_lbl(timedelta())
def tick(self):
# ticks the clock - stops it if time has run out
if self.started is not None:
spent = datetime.now() - self.started
if spent > self.max_duration:
self._stop_clock(spent)
return False
self.update_lbl(spent)
return True
return None
def stop_clock(self):
# stop clock from the outside if <space> is hit
if self.started is not None:
spent = datetime.now() - self.started
self._stop_clock(spent)
def _stop_clock(self, spent):
# internal method that stops the clock, adds total & updates
spent = min(spent, self.max_duration) # fix it
self.total += spent
self.started = None
self.update_lbl(None)
class root(Tk):
def __init__(self):
super(root, self).__init__()
self.title("Chess Clock")
self.minsize(1539,600)
self.windowBG = '#313131'
self.state('zoomed')
self.configure(bg=self.windowBG)
self.CreateWindow()
def CreateWindow(self):
self.grey = ImageTk.PhotoImage(Image.open(r"grey.png"))
self.green = ImageTk.PhotoImage(Image.open(r"green.png"))
# used to determine player
self.turn = 0
# give the clock class the two images to switch
# if changing between active/inactive state
clock.deactive_img = self.grey
clock.active_img = self.green
# one clocks UI
self.white_bg = Label(self, image=self.grey, borderwidth=0)
self.white_bg.place(relx=.3, rely=.55, anchor="center")
self.white = Label(self, text='White', bg='#454545', fg='white', font ="Gadugi 40 bold")
self.white.place(relx=.3, rely=.2, anchor="center")
self.white_timer = Label(self.white_bg, text="", bg='#454545', fg='white', font ="Gadugi 40 bold")
self.white_timer.place(relx=.5, rely=.5, anchor="center")
# seconds clock UI
self.black_bg = Label(self, image=self.grey, borderwidth=0)
self.black_bg.place(relx=.7, rely=.55, anchor="center")
self.black = Label(self, text='Black', bg='#454545', fg='white', font ="Gadugi 40 bold")
self.black.place(relx=.7, rely=.2, anchor="center")
self.black_timer = Label(self.black_bg, text="", bg='#454545', fg='white', font ="Gadugi 40 bold")
self.black_timer.place(relx=.5, rely=.5, anchor="center")
# provide the background-label and the text label
# for time and create two clocks for the players
self.clock1 = clock(1, 5, self.white_bg, self.white_timer)
self.clock2 = clock(1,5, self.black_bg, self.black_timer)
# which clock is currently in use?
self.who_is_it = None
# handles switching to next players clock
self.bind('<space>', lambda _: self.next_player())
self.bind('<Control-Key-q>', lambda _: self.stop())
# check every 200ms if clocks need to be switched over
self.after(200, self.do_clock_logic)
def do_clock_logic(self):
# do nothing if no clock startet
# check if clock has run out, then switch to next players clock
if self.who_is_it is not None:
# tick() returns False if the player spent all his time
# tick() returns True if the player still has time
# tick() returns None if clock is not yet started
if self.who_is_it.tick() == False:
self.next_player()
# recheck clocks in 200ms
self.after(200, self.do_clock_logic)
def stop(self):
"""First Ctrl+q will stop clocks, second will quit."""
if self.who_is_it is not None:
self.who_is_it.stop_clock()
self.who_is_it = None
self.do_clock_logic = lambda _: None is None
else:
self.destroy()
def next_player(self):
if self.who_is_it is not None:
self.who_is_it.stop_clock()
self.turn += 1
# player 1 on "odd turns", player 2 on "even turns"
self.who_is_it = self.clock1 if self.turn % 2 else self.clock2
self.who_is_it.start_clock()
root=root()
root.mainloop()
要获得
在第一个CTRL+q
之后,您将得到结果--第二次CTRL+q
关闭您的窗口:
对于UI/逻辑内容,这可以更好地构建--但它可以作为概念的证明。
https://stackoverflow.com/questions/72328094
复制相似问题