2013-07-09 481 views
2

你好,我想在子程序中創建一個倒數計時器,然後顯示在畫布上。我不完全確定從哪裏開始我已經對它做了一些研究,並且能夠用time.sleep(x)函數創建一個函數,但是該方法凍結了整個程序,這不是我之後。我還在這裏查詢了關於計時器的其他問題,並嘗試將它們合併到我的程序中,但我還沒有取得任何成功。Python - tkinter畫布內的倒數計時器

TLDR;我想創建一個倒數計時器,從60秒倒計時並顯示在畫布上,然後在計時器達到0時執行某些操作。

是否有人能夠將我指向正確的方向?

在此先感謝。

編輯:隨着提供的建議,我試圖把他們沒有多少運氣的程序。

不知道這段代碼是否有重大錯誤,或者它只是一個簡單的錯誤。 我運行它時得到的錯誤在代碼下面。

這是我想在計時器的部分代碼:

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() 

錯誤味精:

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 
+0

你不應該多次調用'mainloop'。此外,每毫秒調用「gamescreen」意味着您每秒創建2000個圖像和2000個條目窗口小部件。 –

+0

我現在已經修好了,我打電話不正確的子程序啓動CD定時器 canvas.after(1,gamescreen) 本來應該 canvas.after(1,cdtimer) 和 canvas.after(1000,遊戲屏幕) 應該是 canvas.after(1000,cdtimer) – ThatsNotMyName

回答

2

這是奧克利答案的擴展。它演示瞭如何顯示在畫布上的時間,以及揭開序幕,整個事情:

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() 

腳本計算從60秒(顯示爲它去剩餘時間),當它擊中0下來,調用do_something。

+0

感謝您的詳細回覆。沒有意識到進口時間不是必需的。 – ThatsNotMyName

+0

我能夠讓代碼在程序中沒有錯誤地運行,但現在我正在遭受堆棧溢出的困擾。我應該能夠解決這個問題後,我重新排列一些線。 – ThatsNotMyName

+1

您不必爲每個勾號清除畫布。您可以創建一次文本項目並使用'itemconfigure'來更改每個打勾的文本值。可以說,如果你所做的只是顯示時間,標籤小部件比畫布更容易使用。 –

2

您要使用的after方法。邏輯是這樣的:

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

以上將從計數器中減去一。如果計數器爲零,它會做一些特殊的事情。否則,它會安排自己在一秒鐘內再次運行。

-1

你可能想嘗試線程?

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,()) 

只要改變sec初始金額(單位:秒),並n到您希望它更新(以秒爲單位)的時間間隔。

+0

線程?對於一個簡單的櫃檯?這對於這樣一個簡單的問題增加了太多的複雜性。另外,線程無法直接更新Tkinter GUI,因此您必須增加更多的複雜性以便在具有隊列的線程和某種輪詢機制之間進行通信。 –