我制作了一个倒计时计时器,每当我按下键盘上的空格键时,计时器就会启动,但问题是,在计时器结束之前,我无法对程序执行任何操作.我想让它在第二次按下空格键时暂停.

我制作的倒计时计时器在一个while循环中工作,该循环在计时器达到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

推荐答案

您可以通过大量重构代码来解决这个问题.您可以向小部件添加2个时钟,每个时钟跟踪自己的花费.空格键侦听器只需在当前使用的时钟之间切换.通过每隔200ms左右设置一个定时do_clock_logic,它会判断是否设置了当前时钟,如果设置了,则判断时间是否已到,如果已到,则切换到另一个时钟.在任何情况下,它都会触发clocks tick()方法来更新其内部状态,这些状态也会处理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()

获取

image of the clock while running

在第一次CTRL+q后,您将获得结果-第二次CTRL+q将关闭窗口:

image after first ctrl+q

这可以在UI/逻辑方面有更好的 struct ,但可以作为概念证明.

Python相关问答推荐

将两个收件箱相连导致索引的列标题消失

在Python中,如何初始化集合列表脚本的输出

从多行文本中提取事件对

Pandas使用过滤器映射多列

如何使用关键参数按列对Pandas rame进行排序

如何将新的SQL服务器功能映射到SQL Alchemy的ORM

为什么基于条件的过滤会导致pandas中的空数据框架?

如何使用矩阵在sklearn中同时对每个列执行matthews_corrcoef?

比较两个二元组列表,NP.isin

从webhook中的短代码(而不是电话号码)接收Twilio消息

使用mySQL的SQlalchemy过滤重叠时间段

根据条件将新值添加到下面的行或下面新创建的行中

如何在箱形图中添加绘制线的传奇?

带条件计算最小值

从numpy数组和参数创建收件箱

更改键盘按钮进入'

DataFrames与NaN的条件乘法

使用特定值作为引用替换数据框行上的值

lityter不让我输入左边的方括号,'

Matplotlib中的字体权重