我想要多个点击事件同时启动定时器,这可能吗?如何实现?

0 投票
2 回答
580 浏览
提问于 2025-04-18 12:04

我正在写我的第一个真正的程序,但遇到了一些问题。我想要能够在不同的时间点击多个标签,而不会在点击新的标签时停止之前的标签。一开始我觉得这个问题很简单,但在阅读了一些资料后,我发现事情比我想的要复杂得多。请问异步代码能解决我的问题吗?如果不能,那还有什么办法呢?顺便说一下,代码编译得很好,运行也没问题,除了我明显遇到的问题。

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

撰写回答