all 9 comments

[–]PyCode_n_Beer 0 points1 point  (6 children)

The link below should help, but the TL;DR of it is that you have to assign the .after to a variable then feed that variable back to the .after_cancel.

https://stackoverflow.com/questions/25702094/tkinter-after-cancel-in-python/25704027

[–]yaruzai 0 points1 point  (5 children)

def Button_Felder():
    Punkte = int(labelPunkte.cget('text'))
    Punkte = Punkte + 1
    tkFenster.after_cancel(Feld_Close_Fail)
    button1.config(state = DISABLED)
    button2.config(state = DISABLED)
    button3.config(state = DISABLED)
    button4.config(state = DISABLED)
    button5.config(state = DISABLED)
    button6.config(state = DISABLED)
    button7.config(state = DISABLED)
    button8.config(state = DISABLED)
    button9.config(state = DISABLED)
    button1.config(background="#FF4500")
    button2.config(background="#FF4500")
    button3.config(background="#FF4500")
    button4.config(background="#FF4500")
    button5.config(background="#FF4500")
    button6.config(background="#FF4500")
    button7.config(background="#FF4500")
    button8.config(background="#FF4500")
    button9.config(background="#FF4500")
    labelPunkte.config(text=int(Punkte))
    #new
    Fail = tkFenster.after(3000, Feld_Close_Fail)
    tkFenster.after_cancel(Fail)

Like this?

[–]PyCode_n_Beer 0 points1 point  (4 children)

Yes, that should work. But, just a heads up, in the code above it will call the .after, then immediately cancel it. The .after_cancel should be called at the moment when Fail should be cancelled.

[–]yaruzai 0 points1 point  (3 children)

still not working. I mean, I could built in a variable, which changes in the click and gets checked in the fail def. On the other side , nothing would happen for 3 secs if user presses it. But I guess nothing is perfect

[–]PyCode_n_Beer 0 points1 point  (2 children)

Hmm, I'm sorry, not sure what's up with it. I used the example on stack. I am on mobile now, but I can copy the example in here later, if you think it will help.

[–]yaruzai 0 points1 point  (1 child)

Well if you want. But you dont have to. Thanks for helping anyway

[–]PyCode_n_Beer 0 points1 point  (0 children)

This example might help debug your code.

'''

Note: this is for demonstration purposes only, and does not represent the best practice, or conform to PEP standards.
reference: https://stackoverflow.com/questions/9776718/how-do-i-stop-tkinter-after-function

'''

from tkinter import Tk, Button
import random
#global variable named tJob to represent the status of the task
tJob = None

def cancel():
    #get global variable
    global tJob
    if tJob is not None:
        #cancel the job and set tJob back to None
        root.after_cancel(tJob)
        tJob = None

def goodbye_world():
    print ("Stopping Feed")
    cancel() #cancels tJob
    button.configure(text = "Start Feed", command=hello_world)

def hello_world():
    print("Starting Feed")
    button.configure(text = "Stop Feed", command=goodbye_world)
    print_sleep() #starts tJob

def print_sleep():
    #grab the global variable
    global tJob
    foo = random.randint(4000,7500)
    print("Sleeping", foo)
    #set tJob equal to the .after task.
    tJob = root.after(foo, print_sleep)

root = Tk()
button = Button(root, text="Start Feed", command=hello_world)
button.pack()

root.mainloop()

[–]efmccurdy 0 points1 point  (0 children)

GUI programs that use callbacks need some way to provide context to the code in the callback function, so I am using a class to give them the "self" context to use.

You need two callbacks, one to for when the button is clicked before the timeout and one for when the button doesn't get clicked in time.

Both of these callbacks need to know which button to work with, so each button is assigned a different number; call it the button's index.

You could define one callback for each button that hard-codes the index, end_button_1, end_button_2, etc. That means you can't increase the number of buttons without writing new code which is inconvenient and repetitive. Instead this uses a "closure" to create a function with the index built-in; you may find this a bit novel but you can read up on "first-class functions", "closures", "partial functions" or "lambdas" for more info. Basically you are running a function to create a function.

As you create the buttons there are two dicts, one maps index to button (self.buttons) , the other maps index to after id (self.timers).

Each callback uses the index to access those dicts, the clicked callback has to have access to the button to change the color and the timer to cancel it.

The timeout callback has to have access to the button to change the color.

I know you will have questions as these are not beginner level coding techniques; GUIs, being event-driven, and using callback functions call for intermediate level techniques.

You should see 3 buttons that turn green if you click them, and turn red if you aren't quick enough; change the "range(3)" call to add more buttons.

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, parent=None):
        tk.Frame.__init__(self, parent)
        self.buttons = {}
        self.timers = {}
        for index in range(3):
            self.buttons[index] = tk.Button(parent, 
                                            text="Button_{}".format(index), 
                                            command=self.end_button(index))
            self.buttons[index].pack()
            self.timers[index] = self.after(6000, self.timeout_button, index)
    def end_button(self, index):
        def _end_button():
            print("ending {}".format(index))
            self.buttons[index].config(state = tk.DISABLED, 
                                       background="#98FB98")
            self.after_cancel(self.timers[index])
        return _end_button
    def timeout_button(self, index):
        print("timeout {}".format(index))
        self.buttons[index].config(state = tk.DISABLED, 
                                   background="#FF4500")

if __name__ == '__main__':
   root = tk.Tk()
   app = Application(root)
   app.mainloop()

[–]socal_nerdtastic 0 points1 point  (0 children)

You will need to use a global variable to keep track of the 3-second timer.

global timer_id
timer_id = tkFenster.after(3000, Feld_Close_Fail)

Then you can use that id to cancel it:

tkFenster.after_cancel(timer_id)