我想要多个点击事件同时启动定时器,这可能吗?如何实现?
我正在写我的第一个真正的程序,但遇到了一些问题。我想要能够在不同的时间点击多个标签,而不会在点击新的标签时停止之前的标签。一开始我觉得这个问题很简单,但在阅读了一些资料后,我发现事情比我想的要复杂得多。请问异步代码能解决我的问题吗?如果不能,那还有什么办法呢?顺便说一下,代码编译得很好,运行也没问题,除了我明显遇到的问题。
from Tkinter import *
import os
import time
class League_Jungle_Timer(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Jungle Timer by BabyAchilles") # initializes window
self.master.geometry("550x300")
self.pack(expand = YES, fill = BOTH)
self.Label1 = Label(self)
self.Label1 = Label(text = "Blue Buff") #--------------> #Start Tkinter GUI Labels
self.Label1.pack()
self.Label2 = Label(self)
self.Label2 = Label(self, text = "Red Buff")
self.Label2.pack()
self.Label3=Label(self)
self.Label3=Label(self, text = "Dragon",font=("Helvetica", 16))
self.Label3.pack()
self.Button1 = Button(self) #--------------> #Start Tkinter GUI Buttons
self.Button1["text"] = "Blue Buff"
self.Button1["fg"] = "Blue"
self.Button1["command"] = self.label_clicked
self.Button1.pack({"side": "left"})
self.Button2 = Button(self)
self.Button2["text"] = "Red Buff"
self.Button2["fg"] = "Red"
self.Button2["command"] = self.my_timeRB
self.Button2.pack({"side":"right"})
self.Button2.pack(padx=50)
self.Button3 = Button(self)
self.Button3["text"] = " Dragon "
self.Button3["fg"] = "Pink"
self.Button3["bg"] = "Purple"
self.Button3["command"] = self.my_timeDrag
self.Button3.pack(side="bottom",pady=50)
self.Quit = Button(self)
self.Quit["text"] = "Quit"
self.Quit["command"] = self.destroy
self.Quit.pack()
self.Label1.bind("<Button-1>", self.label_clicked)
self.Label2.bind("<Button-3>", self.label2_clicked)
self.Label3.bind("<Double-Button-1>",self.label3_clicked)
##########################################################################
def my_timeDrag(self): # creates a timer starting at 5 min , counts down to 0 then repeats
min_m = 5
sec = 59
while sec <=60:
self.Label3.configure(text="{0}:{1:02}".format(min_m, sec))
self.Label3.update()
os.system('cls')
print min_m, "Minutes", sec, "Seconds"
time.sleep(1)
sec -= 1
if sec == 0:
min_m -= 1
sec = 59
elif min_m == 0:
min_m = 5
##########################################################################################
def my_timeBB(self): # creates a timer starting at 5 min , counts down to 0 then repeats
min_m = 4
sec = 59
while sec <=60:
self.Label1.configure(text="{0}:{1:02}".format(min_m,sec))
self.Label1.update()
os.system('cls')
print min_m, "Minutes", sec, "Seconds"
time.sleep(1)
sec -= 1
if sec == 0:
min_m -= 1
sec = 59
elif min_m == 0:
min_m = 4
#######################################################
def my_timeRB(self): # creates a timer starting at 5 min , counts down to 0 then repeats
_min = 4
sec = 59
while sec <=60:
self.Label2.configure(text="{0}:{1:02}".format(_min,sec))
self.Label2.update()
os.system('cls')
print _min, "Minutes", sec, "Seconds"
time.sleep(1)
sec -= 1
if sec == 0:
_min -= 1
sec = 59
elif _min == 0:
_min = 4
##############################################################
def label_clicked(self, event):
self.Label1.configure(self.my_timeBB())
self.Label1.update()
def label2_clicked(self, event):
self.Label2.configure(self.my_timeRB())
self.Label2.update()
def label3_clicked(self, even):
self.Label3.configure(self.my_timeDrag())
self.Label3.update()
League_Jungle_Timer().mainloop()
2 个回答
0
解决这个问题其实很简单,但有点步骤。
你需要用到Python的多线程和队列库。
首先,你要导入这些库:
import threading
import Queue
接下来,设置线程类:
class ThreadedClient(threading.Thread):
def __init__(self, queue, fcn):
threading.Thread.__init__(self)
self.queue = queue
self.fcn = fcn
def run(self)
time.sleep(1)
self.queue.put(self.fcn())
然后,在你的 League_Jungle_Timer
类里面,添加两个函数。spawnthread
用来设置线程,启动它,然后调用 periodiccall
,这个函数可以让主循环和其他“并发”的函数一起运行。
def spawnthread(self, fcn):
self.thread = ThreadedClient1(self.queue, fcn)
self.thread.start()
self.periodiccall(thread)
def periodiccall(self):
if self.thread.is_alive():
self.after(100, self.periodiccall)
在 League_Jungle_Timer
的初始化方法里,加上这一行来设置队列:
self.queue = Queue.Queue()
使用的时候,可以用 lambda: self.spawnthread(self.my_timeBB())
这样的方式调用,或者调用其他你想要的函数。可以把这个表达式用作按钮的回调或者在标签配置里使用。
2
你可以使用 tk.after()
来实现这个功能。
通过 after(1000, function_name)
,你可以在1000毫秒后运行一个(小)函数,这样不会影响其他函数的运行(前提是你不使用 time.sleep
)。而且这个函数可以使用 after()
再次调用自己。
from Tkinter import *
import os
import time
class League_Jungle_Timer(Frame):
def __init__(self):
Frame.__init__(self)
# initializes window
self.master.title("Jungle Timer by BabyAchilles")
self.master.geometry("550x300")
self.pack(expand=YES, fill=BOTH)
# Start Tkinter GUI Labels
self.label1 = Label(self, text="Blue Buff")
self.label1.pack()
self.label2 = Label(self, text="Red Buff")
self.label2.pack()
self.label3=Label(self, text="Dragon", font=("Helvetica", 16))
self.label3.pack()
# Start Tkinter GUI Buttons
self.Button1 = Button(self, text="Blue Buff", fg="Blue", command=self.my_timeBB)
self.Button1.pack(side="left")
self.Button2 = Button(self, text="Red Buff", fg="Red", command=self.my_timeRB)
self.Button2.pack(side="right", padx=50)
self.Button3 = Button(self, text=" Dragon ", fg="Pink", bg="Purple", command=self.my_timeDrag)
self.Button3.pack(side="bottom",pady=50)
self.Quit = Button(self, text="Quit", command=self.destroy)
self.Quit.pack()
self.label1.bind("<Button-1>", self.label_clicked)
self.label2.bind("<Button-3>", self.label2_clicked)
self.label3.bind("<Double-Button-1>",self.label3_clicked)
self.timer_id_DR = None
self.timer_id_RB = None
self.timer_id_BB = None
#######################################################
# creates a timer starting at 5 min , counts down to 0 then repeats
def my_timeDrag(self):
self.my_timeDrag_time = [4, 59]
if self.timer_id_DR:
self.after_cancel(self.timer_id_DR)
self.timer_id_DR = None
self.my_timeDrag_after()
def my_timeDrag_after(self):
m, s = self.my_timeDrag_time
self.label3.configure(text="{0}:{1:02}".format(m, s))
self.label3.update()
#os.system('cls')
print "DR", m, "Minutes", s, "Seconds"
s -= 1
if s == 0:
m -= 1
s = 59
elif m == 0:
m = 5
self.my_timeDrag_time = [m, s]
self.timer_id_DR = self.after(1000, self.my_timeDrag_after)
#######################################################
# creates a timer starting at 5 min , counts down to 0 then repeats
def my_timeBB(self):
self.my_timeBB_time = [4, 59]
if self.timer_id_BB:
self.after_cancel(self.timer_id_BB)
self.timer_id_BB = None
self.my_timeBB_after()
def my_timeBB_after(self):
m, s = self.my_timeBB_time
self.label1.configure(text="{0}:{1:02}".format(m, s))
self.label1.update()
#os.system('cls')
print "BB", m, "Minutes", s, "Seconds"
s -= 1
if s == 0:
m -= 1
s = 59
elif m == 0:
m = 5
self.my_timeBB_time = [m, s]
self.timer_id_BB = self.after(1000, self.my_timeBB_after)
#######################################################
def my_timeRB(self):
self.my_timeRB_time = [4, 59]
#if self.timer_id_RB:
self.after_cancel(self.timer_id_RB)
#self.timer_id_RB = None
self.my_timeRB_after()
def my_timeRB_after(self):
m, s = self.my_timeRB_time
self.label2.configure(text="{0}:{1:02}".format(m, s))
self.label2.update()
#os.system('cls')
print "RB", m, "Minutes", s, "Seconds"
s -= 1
if s == 0:
m -= 1
s = 59
elif m == 0:
m = 5
self.my_timeRB_time = [m, s]
self.timer_id_BB = self.after(1000, self.my_timeRB_after)
#######################################################
def label_clicked(self, event):
self.label1.configure(self.my_timeBB())
self.label1.update()
def label2_clicked(self, event):
self.label2.configure(self.my_timeRB())
self.label2.update()
def label3_clicked(self, even):
self.label3.configure(self.my_timeDrag())
self.label3.update()
##############################################################
League_Jungle_Timer().mainloop()