0

Using tkinter, I wish to create a Button, when pressed it delays its switching in x seconds.

using time.sleep(x), pauses entire program, which is not my intention.

how can it be done ?

followed- class of the "button"( has a checkbutton widget, a labelwidget showing on/off label, and an entry widget to enter amount of seconds to delay )

class dev_buttons2(object):
  def __init__(self,master,buts_list):
    self.status=[]
    self.buts=[]
    self.leds=[]
    for i in range(len(buts_list)):
        var = StringVar()
        c = Checkbutton(master,text=buts_list[i], variable=var,
        indicatoron=0,command=lambda arg=[buts_list[i],var]: 
        self.cb(arg),width=10,height=2,onvalue="on",offvalue="off")
        c.grid(column=i, padx=30,pady=5,row = 1)
        var.set("off")

        var1=IntVar()
        ent=Entry(master,textvariable=var1,width=4)
        ent.grid(column=i,row=2)

        var2=StringVar()
        led=Label(master,textvariable=var2,width=4,bg="red",fg="white",
        relief="ridge")
        var2.set("off")
        led.grid(row=0,column=i)

        self.status.append([var,var2,var1])           
        self.buts.append(c)
        self.leds.append(led)

  def cb(self,but):
    indx=devices_headers.index(but[0])
    if but[1].get()=="on":
        self.status[indx][1].set(but[1].get())
        self.leds[indx].config(bg="green")
        if self.status[indx][2].get() !=0:
            print(self.status[indx][2].get() )

    if but[1].get()=="off":
        self.status[indx][1].set(but[1].get())
        self.leds[indx].config(bg="red")

a try to update cb function - gets the delay, but doen'st delay:

def cb(self,but):
    print(but[2].get())   ###(but[2] contains var1.get() -- timeout for opretion
    indx=devices_headers.index(but[0])
    device_chage_state(indx,but[1].get())
    if but[2].get() >0 :
        print ("switch off in %d seconds"%self.status[indx][2].get())
        root.after(but[2].get(),self.cb,but)

Pics of relevant part in GUI shows each button have a timeout Entry, when entered (greater than 0 ) will turn off after amount of seconds entered Manual switch pannel description

1 Answer 1

2

Since you are using tkinter, the best way to do that is using the after() method. You can for example add a method like this:

def cb_delayed(self, master, but, delay_ms_var):
    master.after(delay_ms_var.get(), self.cb, but)

And then in the button creation change:

# ...
c = Checkbutton(
    master, text=buts_list[i], variable=var, indicatoron=0,
    command=lambda arg=[buts_list[i],var]: self.cb_delayed(master, arg, delay_ms_var),
    width=10, height=2, onvalue="on", offvalue="off")
# ...

Where delay_ms_var is the tkinter variable object containing the delay in milliseconds that you want to have before the change happens.

Sign up to request clarification or add additional context in comments.

8 Comments

thanks for your answer- I have some questions : 1) CheckButton's command can transfer only one variable ( so I used lambda and arg=[but_list,var]) - so how DELAY_MS is transfered to cd_delayed function ? 2)cb_delayed has master in its definition. can you explain what is the purpose of using it ?
1) I thought the delay was meant to be a fixed amount of time. I've changed the answer to use a variable object instead. This can be passed just like that or added to arg if you prefer; since tkinter variables are prone to cause problems when they are garbage collected, it could be better in your case. 2) master is needed in cb_delayed in order to call .after; however, if that object is accessible from a global variable or from self, you may not need to pass it as a parameter.
thanks for your update- you can see a pic of GUI attached to Question. 1) delay_ms_var is var1 in my code. when pressing any button- the value of var1 passed to cb_delayed belongs to last button (#4) - that is why i constructed arg since there I didn't find any alternative way to pass values. can you explain ?
@Guy.D The parameter command is a function (or lambda, or callable in general) that is called by Tk when the button is pressed. If you use a lambda, you can specify a call with arguments from the local variables of the function (or global variables). See this question, for example.
@Guy.D The lambda function receives no parameters from tkinter; in your case your lambda is receiving arg because it has a default value. However, the lambda itself is free to call any function with however many parameters; it is not tkinter the one that calls cb / cb_delayed, but your lambda, so you have full control over the parameters these functions receive. Here are more examples of callbacks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.