Basically, I am currently writing a python program (technically its a game) in which a certain (TKinter Widget) button should only be able to be clicked every 1 second. here is an example of what I mean:
import time
from tkinter import *
def button_click():
button["state"] = DISABLED
print("button clicked! Please wait 1 second...")
time.sleep(1)
button["state"] = NORMAL
root = Tk()
button = Button(root, text="Click Me!", command=button_click)
button.pack() #Please Dont Tell Me Not To Use Pack() ; I Use Place()
So anyways, for example, when running this program, if I just keep clicking the button, it will increase the count by 1 each second. instead, I would like it to not count all the clicks that happen between the first click, and 1 second after that.
It is because the tkinter does not take control when the button is disabled, so it is not updated. You need to call, for example, button.update() after it is disabled to force the update:
def button_click():
button["state"] = DISABLED
button.update() # force the update
print("button clicked! Please wait 1 second...")
time.sleep(1)
button["state"] = NORMAL
However, it is better to use after() instead of time.sleep():
def button_click():
button["state"] = DISABLED
print("button clicked! Please wait 1 second...")
# enable the button after one second
button.after(1000, lambda: button.config(state='normal'))
Maybe you forgot the "root.mainloop" at the end of the code.
import time
from tkinter import *
def button_click():
button["state"] = DISABLED
print("button clicked! Please wait 1 second...")
time.sleep(1)
button["state"] = NORMAL
root = Tk()
button = Button(root, text="Click Me!", command=button_click)
button.pack()
root.mainloop()
This works for me. You can only press the button every 1 second.
Related
I am new to tkinter, I am trying to make a button that flashes green and silver until it is pressed, at which point it reverts to silver. I followed the code from this website, flash button example, it seemed to be closest to what I was trying to do.
%reset -f
import tkinter as tk
root = tk.Tk()
def stop_flash():
print('stop_flash')
root.after_cancel(flasher2)
root.after_cancel(flasher1)
button = tk.Button(root, text="Hello", command=stop_flash, background='silver', activebackground='red')
button.pack()
def flash():
button.configure(background = 'green')
flasher1 = root.after(500, lambda: button.configure(background = 'silver'))
flasher2 = root.after(1000, flash)
flasher1 = root.after(500, lambda: button.configure(background = 'silver'))
flasher2 = root.after(1000, flash)
root.mainloop()
I got the button to flash but I don't understand why it won't stop. I have tried making a separate switch button so I would only need to use 1 after() function but it gets even messier. Any help here would be greatly appreciated!!!!!
here is my sample code:
from time import sleep
import tkinter as tk
import threading
class Action:
counter = 0
def do_something(self):
while True:
print('Looping')
sleep(5)
action = Action()
root = tk.Tk()
button = tk.Button(root, text='pressme harder', command=threading.Thread(target=action.do_something()).start())
button.grid(row=1, column=0)
root.mainloop()
What am I expecting?
I'm expecting that as soon as I click the button in the UI an new thread is running, which is looping in the background and does not interfere with the UI (or later maybe other threads doing tasks in the background)
What is really happening?
When running the code, the method of the class is executeds immdiately and locking the procedure. root.mainloop() is never reached and therefore no UI is drawn
Alternatively I tried the following change:
button = tk.Button(root, text='pressme harder', command=threading.Thread(target=lambda: action.do_something()).start())
This behaves in the following (imho wrong) way:
The method is also called immediately, without pressing the button. This time the UI is drawn but seems the be locked by the thread (UI is slow/stuttering, pressing the buttom does not work most of the time)
Any Idea whats wrong there? Or how do I handle this in a more stable way?
You shouldn't try to start a thread directly in the button command. I suggest you create another function that launches the thread.
from time import sleep
import tkinter as tk
import threading
class Action:
counter = 0
def do_something(self):
while True:
print('Looping')
sleep(2)
print("Finished looping")
def start_thread(self):
thread = threading.Thread(target=self.do_something, daemon=True)
thread.start()
action = Action()
root = tk.Tk()
button = tk.Button(root, text='pressme harder', command=action.start_thread)
button.grid(row=1, column=0)
root.mainloop()
I'm trying to make a button where it will start a program. So first, a button called 'Run' will appear, subsequently after 3 seconds it should come up with a new button that says 'Stop'.
The reason I want it that way. That it's because I have tried and add two buttons on an interface panel, but the problem is then, every time I run an application, the interface freezes, so it was not possible to 'Stop' the program. So, I was wondering if it would be possible to do something like that?
What I've done:
from tkinter import *
tkWindow = Tk()
tkWindow.geometry('150x50')
tkWindow.title('Tkinter Example')
print("Tkinter button is appearing...")
def Action():
from Launch import Launch
run = Launch()
run
def Off():
import sys
sys.exit()
button = Button(tkWindow,
text='Start',
command=Action)
button1 = Button(tkWindow,
text='Stop',
command=Off)
button.pack()
button1.pack()
tkWindow.mainloop()
Try something like this:
from tkinter import *
from threading import Thread
from Launch import Launch
tkWindow = Tk()
tkWindow.geometry('150x50')
tkWindow.title('Tkinter Example')
print("Tkinter button is appearing...")
def Action():
thread = Thread(target=Launch, daemon=True)
thread.start()
# If you want to disable the button use:
# button.config(state="disabled")
button = Button(tkWindow,
text='Start',
command=Action)
# Here I am going to use the built-in `exit` function as per #Matiiss' suggestion
button1 = Button(tkWindow,
text='Stop',
command=exit)
button.pack()
button1.pack()
tkWindow.mainloop()
It starts a new thread when the "Start" button is pressed. That new thread calls Launch, leaving the main thread for tkinter. Please make sure that there isn't any references to your main GUI in your Launch function.
I have a simple program with start and exit buttons. The start button makes a notification using win10toast, but the button remains visibly pressed down and the window becomes unresponsive. The exit button works fine before the start button is pressed. Here's my code:
from tkinter import *
from win10toast import ToastNotifier
root = Tk()
def exit_p():
exit()
def new():
hr.show_toast("New", "Alert")
return
#creates a label widget
myLabel1 = Label(root, text="Full Moon Notification!")
myLabel2 = Label(root, text="Here you can start and exit the program")
button1 = Button(root, text="Start",padx=50,command=new).grid(row=3,column=0)
button2 = Button(root, text="Exit", padx=50,command=exit_p).grid(row=4,column=0)
#puts the widget on the screen
myLabel1.grid(row=0,column=0)
myLabel2.grid(row=1,column=0)
#loop to keep program running
root.mainloop()
The issue is likely because hr.show_toast("New", "Alert") blocks.
The win10toast library conveniently provides an option threaded=True, so just change that code to
hr.show_toast("New", "Alert", threaded=True)
should make it work.
I want the button to start the command, then be disabled while executing and enabled again after the execution finished.
When I click the button, it appears to be disabled and the command is executed. But when I click the button while it is disabled, the command is executed a second time after it finished the first execution.
It seems like after the second click, the button is really disabled because I can click several times while it's disabled and it's only repeated once.
import tkinter as tk
import time
class Button:
def __init__(self, master):
frame=tk.Frame(master)
frame.pack()
self.button1=tk.Button(frame, text="Ready",bg="green", fg="white", command=self.click)
self.button1.pack()
def click(self):
self.button1.config(bg="red", text="Busy", state="disabled")
self.button1.update()
doSth()
self.button1.config(bg="green", fg="white", text="Ready", state="normal")
self.button1.update()
def doSth():
time.sleep(3)
print("done")
root = tk.Tk()
b = Button(root)
root.mainloop()
When you click the button during the sleep, you queue a button click to be processed in the next update cycle. During the sleep tkinter doesn't update. After the sleep, you change the button back to normal state before the function returns and the click is processed. Since the button is active again, click is called again.
You can counter this by letting tkinter update before you activate the button again, this gets rid of any queued click events while the button still is deactivated.
def click(self):
self.button1.config(bg="red", text="Busy", state="disabled")
self.button1.update()
doSth()
self.button1.update()
self.button1.config(bg="green", fg="white", text="Ready", state="normal")