Python - Countdown timer within a tkinter canvas

2019-02-25 16:39发布

Hello I would like to create a countdown timer within a subroutine which is then displayed on the canvas. I'm not entirely sure of where to begin I've done some research on to it and was able to make one with the time.sleep(x) function but that method freezes the entire program which isn't what I'm after. I also looked up the other questions on here about a timer and tried to incorporate them into my program but I wasn't able to have any success yet.

TLDR; I want to create a countdown timer that counts down from 60 seconds and is displayed on a canvas and then have it do something when the timer reaches 0.

Is anyone able to point me in the right direction?

Thanks in advance.

EDIT: With the suggestions provided I tried to put them into the program without much luck.

Not sure if there is a major error in this code or if it's just a simple mistake. The error I get when I run it is below the code.

This is the part of the code that I want the timer in:

def main(): #First thing that loads when the program is executed.
   global window
   global tkinter
   global canvas
   global cdtimer
   window = Tk()
   cdtimer = 60
   window.title("JailBreak Bob")

   canvas = Canvas(width = 960, height = 540, bg = "white")
   photo = PhotoImage(file="main.gif")
   canvas.bind("<Button-1>", buttonclick_mainscreen)
   canvas.pack(expand = YES, fill = BOTH)
   canvas.create_image(1, 1, image = photo, anchor = NW)
   window.mainloop()

def buttonclick_mainscreen(event):
   pressed = ""

   if event.x >18 and event.x <365 and event.y > 359 and event.y < 417 : pressed = 1 
   if event.x >18 and event.x <365 and event.y > 421 and event.y < 473 : pressed = 2 
   if event.x >18 and event.x <365 and event.y > 477 and event.y < 517 : pressed = 3 

   if pressed == 1 :
     gamescreen()
   if pressed == 2 :
     helpscreen()
   if pressed == 3 :
     window.destroy()

def gamescreen():
  photo = PhotoImage(file="gamescreen.gif")
  canvas.bind("<Button-1>", buttonclick_gamescreen)
  canvas.pack(expand = YES, fill = BOTH)
  canvas.create_image(1, 1, image = photo, anchor = NW)
  game1 = PhotoImage(file="1.gif")
  canvas.create_image(30, 65, image = game1, anchor = NW)
  e1 = Entry(canvas, width = 11)
  e2 = Entry(canvas, width = 11) 
  canvas.create_window(390, 501, window=e1, anchor = NW)
  canvas.create_window(551, 501, window=e2, anchor = NW)
  canvas.after(1, gamescreen)
  window.mainloop()

def cdtimer():
  canvas.delete(ALL)
  global cdtimer
  cdtimer -= 1
  canvas.create_text(510, 6, text=cdtimer, font="Ubuntu 29 bold", anchor = NW) 
  if cdtimer == 0:
    scorescreen()
  else:
    canvas.after(1000, gamescreen)

main()

Error MSG:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.2/tkinter/__init__.py", line 1402, in __call__
    return self.func(*args)
  File "/usr/lib/python3.2/tkinter/__init__.py", line 490, in callit
    func(*args)
  File "/home/ppppwn3d/workspace/Python/JailBreakBob/JailBreakBob.py", line 50, in     gamescreen
    e1 = Entry(canvas, width = 11)
  File "/usr/lib/python3.2/tkinter/__init__.py", line 2372, in __init__
    Widget.__init__(self, master, 'entry', cnf, kw)
  File "/usr/lib/python3.2/tkinter/__init__.py", line 1952, in __init__
    cnf = _cnfmerge((cnf, kw))
  File "/usr/lib/python3.2/tkinter/__init__.py", line 71, in _cnfmerge
    if isinstance(cnfs, dict):
RuntimeError: maximum recursion depth exceeded while calling a Python object

3条回答
Lonely孤独者°
2楼-- · 2019-02-25 16:53

You want to use the after method. The logic goes something like this:

def update_clock(self):
    self.counter -= 1
    if self.counter == 0 :
        do_something()
    else:
        self.after(1000, self.update_clock)

The above will subtract one from the counter. If the counter is zero it does something special. Otherwise, it schedules itself to run again in one second.

查看更多
我命由我不由天
3楼-- · 2019-02-25 16:57

You might want to try threading?

import thread
import time

def myFunct():
    sec = 60
    n = 1
    for i in range(sec/n):
        updateClock()
        time.sleep(n)
    finalFunct()

thread.start_new_thread(myFunct, ())

Just change sec to the initial amount (in seconds), and n to the interval at which you want it to update (in seconds).

查看更多
在下西门庆
4楼-- · 2019-02-25 17:02

This is an expansion of Oakley's answer. It demonstrates how to display the time in a canvas as well as kick off the whole thing:

from tkinter import *
root = Tk()
canvas = Canvas(root)
canvas.pack()
time = 60
def tick():
    # You have to clear the canvas each time the clock updates 
    # (otherwise it writes on top of the old time).  Since the
    # time is the only thing in the canvas, delete(ALL) works
    # perfectly (if it wasn't however, you can delete the id
    # that goes with the clock).
    canvas.delete(ALL)
    # I have to declare time as a global because I'm not using
    # a class (otherwise, I could do something like self.time -= 1)
    global time
    time -= 1
    # You can place the time wherever in the canvas
    # (I chose 10,10 for the example)
    canvas.create_text(10, 10, text=time)
    if time == 0:
        do_something()
    else:
        canvas.after(1000, tick)
canvas.after(1, tick)
root.mainloop()

The script counts down from 60 seconds (displaying the remaining time as it goes) and, when it hits 0, it calls do_something.

查看更多
登录 后发表回答