I'm making a mining game and whenever a user clicks 'mine' button, I want it to disable so the user cant click it again until cool down wears off. I made a sample of the code, I state the definition first, then make the button, but since the button is after, the def doesn't know what variable the 'mine' button is. Any help appreciated!
root = Tk()
def def1():
btn[state] = 'disabled'
Btn = Button(root, text="button", command= def1())
root.mainloop()```
Try this:
import tkinter as tk
def enable_btn():
btn.config(state="normal")
def def1():
print("Clicked")
btn.config(state="disabled")
# 1000 is the cooldown in ms (so 1000 = 1 sec)
btn.after(1000, enable_btn)
root = tk.Tk()
btn = tk.Button(root, text="button", command=def1)
btn.pack()
root.mainloop()
I am using a .after script so the enable_btn function runs 1 sec after def1 is called.
Related
I am a Python beginning self-learner, running on MacOS.
I'm making a program with a text parser GUI in tkinter, where you type a command in a Entry widget, and hit a Button widget, which triggers my parse() funct, ect, printing the results to a Text widget, text-adventure style.
> Circumvent the button
I can't let you do that, Dave.
I'm trying to find a way to get rid of the need to haul the mouse over to the Button every time the user issues a command, but this turned out harder than I thought.
I'm guessing the correct code looks like self.bind('<Return>', self.parse())? But I don't even know where to put it. root, __init__, parse(), and create_widgets() don't want it.
To be clear, the only reason anyone should hit enter in the prog is to trigger parse(), so it doesn't need to be espoused to the Entry widget specifically. Anywhere it works is fine.
In response to 7stud, the basic format:
from tkinter import *
import tkinter.font, random, re
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master, ...)
self.grid()
self.create_widgets()
self.start()
def parse(self):
...
def create_widgets(self):
...
self.submit = Button(self, text= "Submit Command.", command= self.parse, ...)
self.submit.grid(...)
root = Tk()
root.bind('<Return>', self.parse)
app = Application(root)
root.mainloop()
Try running the following program. You just have to be sure your window has the focus when you hit Return--to ensure that it does, first click the button a couple of times until you see some output, then without clicking anywhere else hit Return.
import tkinter as tk
root = tk.Tk()
root.geometry("300x200")
def func(event):
print("You hit return.")
root.bind('<Return>', func)
def onclick():
print("You clicked the button")
button = tk.Button(root, text="click me", command=onclick)
button.pack()
root.mainloop()
Then you just have tweak things a little when making both the button click and hitting Return call the same function--because the command function needs to be a function that takes no arguments, whereas the bind function needs to be a function that takes one argument(the event object):
import tkinter as tk
root = tk.Tk()
root.geometry("300x200")
def func(event):
print("You hit return.")
def onclick(event=None):
print("You clicked the button")
root.bind('<Return>', onclick)
button = tk.Button(root, text="click me", command=onclick)
button.pack()
root.mainloop()
Or, you can just forgo using the button's command argument and instead use bind() to attach the onclick function to the button, which means the function needs to take one argument--just like with Return:
import tkinter as tk
root = tk.Tk()
root.geometry("300x200")
def func(event):
print("You hit return.")
def onclick(event):
print("You clicked the button")
root.bind('<Return>', onclick)
button = tk.Button(root, text="click me")
button.bind('<Button-1>', onclick)
button.pack()
root.mainloop()
Here it is in a class setting:
import tkinter as tk
class Application(tk.Frame):
def __init__(self):
self.root = tk.Tk()
self.root.geometry("300x200")
tk.Frame.__init__(self, self.root)
self.create_widgets()
def create_widgets(self):
self.root.bind('<Return>', self.parse)
self.grid()
self.submit = tk.Button(self, text="Submit")
self.submit.bind('<Button-1>', self.parse)
self.submit.grid()
def parse(self, event):
print("You clicked?")
def start(self):
self.root.mainloop()
Application().start()
Another alternative is to use a lambda:
ent.bind("<Return>", (lambda event: name_of_function()))
Full code:
from tkinter import *
from tkinter.messagebox import showinfo
def reply(name):
showinfo(title="Reply", message = "Hello %s!" % name)
top = Tk()
top.title("Echo")
Label(top, text="Enter your name:").pack(side=TOP)
ent = Entry(top)
ent.bind("<Return>", (lambda event: reply(ent.get())))
ent.pack(side=TOP)
btn = Button(top,text="Submit", command=(lambda: reply(ent.get())))
btn.pack(side=LEFT)
top.mainloop()
As you can see, creating a lambda function with an unused variable "event" solves the problem.
I found one good thing about using bind is that you get to know the trigger event: something like: "You clicked with event = [ButtonPress event state=Mod1 num=1 x=43 y=20]" due to the code below:
self.submit.bind('<Button-1>', self.parse)
def parse(self, trigger_event):
print("You clicked with event = {}".format(trigger_event))
Comparing the following two ways of coding a button click:
btn = Button(root, text="Click me to submit", command=(lambda: reply(ent.get())))
btn = Button(root, text="Click me to submit")
btn.bind('<Button-1>', (lambda event: reply(ent.get(), e=event)))
def reply(name, e = None):
messagebox.showinfo(title="Reply", message = "Hello {0}!\nevent = {1}".format(name, e))
The first one is using the command function which doesn't take an argument, so no event pass-in is possible.
The second one is a bind function which can take an event pass-in and print something like "Hello Charles! event = [ButtonPress event state=Mod1 num=1 x=68 y=12]"
We can left click, middle click or right click a mouse which corresponds to the event number of 1, 2 and 3, respectively. Code:
btn = Button(root, text="Click me to submit")
buttonClicks = ["<Button-1>", "<Button-2>", "<Button-3>"]
for bc in buttonClicks:
btn.bind(bc, lambda e : print("Button clicked with event = {}".format(e.num)))
Output:
Button clicked with event = 1
Button clicked with event = 2
Button clicked with event = 3
This worked for me while assigning buttons to functions.
Create a function to set buttons to other functions:
def enter(event=clr):
but_ch['command'] = clr
Then bind the function to the root and invoke:
root.bind('<Return>', lambda enter: but_ch.invoke())
I have read numerous questions here but none actually answered my puzzle:
openFolderBtnGenerate = Button(top, text="Generate", command=lambda: compute(csv_file_name, lan, lon, alt))
openFolderBtnGenerate.grid(row=5, column=1)
def compute(csv_file_name, lat_0, lon_0, alt_0):
global openFolderBtnGenerate
openFolderBtnGenerate['text'] = "Please wait..."
# here mathematical computation code that takes 10 seconds to accomplish
...
# end
I intended the button text to change before the computation starts so users understand it might take some time to accomplish.
What really happens is that the button text is changed only after the computation ends.
How can I make the button text change right after the button is clicked, without having to wait these long 10 seconds?
What I think you want to do is just to change text as you press the button then run the function, so a small thing you can do is make another function CODE :
Def function2()
global openFolderBtnGenerate
openFolderBtnGenerate['text'] = "Please wait..."
compute(csv_file_name, lan, lon, alt)
openFolderBtnGenerate = Button(top, text="Generate", command=function2)
openFolderBtnGenerate.grid(row=5, column=1)
def compute(csv_file_name, lat_0, lon_0, alt_0):
# here mathematical computation code that takes 10 seconds to accomplish
...
# end
It works for me and will surely work for you too.
See line "root.update_idletasks()":
import time
import tkinter as tk
root = tk.Tk()
def start_task():
btn_text.set("Please wait for task to finish...")
btn.update_idletasks()
time.sleep(2)
btn_text.set("Press to start a task")
btn_text = tk.StringVar()
btn = tk.Button(root, textvariable=btn_text, command=start_task)
btn_text.set("Press to start a task")
btn.pack()
root.mainloop()
And another sample, without time.sleep() (for UI not to freeze):
import time
import tkinter as tk
root = tk.Tk()
def update_text():
btn_text.set("Press to start a task")
def start_task():
btn_text.set("Please wait for task to finish...")
btn.update_idletasks()
root.after(2000, update_text)
btn_text = tk.StringVar()
btn = tk.Button(root, textvariable=btn_text, command=start_task)
btn_text.set("Press to start a task")
btn.pack()
root.mainloop()
I have two widgets to work with, a text input, and a button, both are created inside a function. What I want to happen is the user types in their name and then clicks the button to submit the answer. What I want the computer to do, is on the button press it will read whats inside the text and the save it to a variable. Once it saves it, it will print it out.
The code below is bad because it runs through the if statement immediately without the consulting of the button press.
There has to be a simpler solution. Also this may not be PEP 8 or whatever please be patient because I'm new.
import tkinter as tk
from tkinter import Tk, Label, Button
import sys
import time
import random
import threading
from tkinter import *
window = tk.Tk()
window.geometry("300x300")
window.title("GUI")
def start_screen():
reset()
start = tk.Label(window, text="start of game")
start.place(x=110,y=20)
play = Button(window, text= "play", command = start_game)
play.place(x=110,y=50)
helper = Button(window, text="help", command = help_screen)
helper.place(x=110,y=70)
def stuff():
global t
t = True
print(t)
return t
def text_handling():
global t
t = False
reset()#clears the screen
label = Label(window, text='')
question1= "what is your name?"
label.pack()
print_slow(label, question1, 40)#prints out letters slowly
#here is the part I'm having problems with
name = Entry(window)
name.pack()
but = Button(window, text="enter", command= stuff)
but.pack()
print(t)
if t == True:
myPlayer.name = name.get()
print(myPlayer.name)
def start_game():
reset()
bt = tk.Button(window,text="Enter", bg="orange", command =
text_handling)
bt.place(x=100,y=100)
start_screen()
I am currently working on a little just for fun project, which pretends it´s generating something and then shows a specific message, but I have a question: As soon as I press the button on the screen it is showing a progressbar, that is what I want it to do, but if I press the button again it just shows the same thing again and again, is there any way to prevent the program from printing the Starting the generate text and the progressbar multiple times?
Here´s the code:
# my little import area
import tkinter as tk
from tkinter import ttk
# Initialization
win = tk.Tk()
win.title("StackOverflow")
# Window Size
win.resizable(False, False)
win.minsize(750,500)
# Button clicked command
def buttonclicked():
tk.Label(win, text="Starting to generate...").pack()
pb.pack()
pb.start(500)
#Widgets
headerlabel = tk.Label(win, text="StackOverFlow Question")
generatebutton = tk.Button(win, text="Generate", command=buttonclicked)
pb = ttk.Progressbar(win, orient="horizontal", length=250, mode="determinate")
#Positioning
headerlabel.pack()
generatebutton.pack()
win.mainloop()
You can put
global generatebutton
generatebutton.config(state='disabled')
in your buttonclicked function (which is stupid because the global keyword is usually SO BAD to use, it turns your code into nightmare), or use OOP to your advantage. You can also use win.destroy() or generatebutton.destroy().
Here is that more OOP-intensive code example:
import tkinter as tk
from tkinter import ttk
class Joke:
def __init__(self):
self.win = tk.Tk()
self.win.title("StackOverflow")
self.win.resizable(False, False)
self.win.minsize(750,500)
headerlabel = tk.Label(self.win, text="StackOverFlow Question")
self.generatebutton = tk.Button(self.win, text="Generate", command=self.buttonclicked)
self.pb = ttk.Progressbar(self.win, orient="horizontal", length=250, mode="determinate")
headerlabel.pack()
self.generatebutton.pack()
self.win.mainloop()
def buttonclicked(self):
tk.Label(self.win, text="Starting to generate...").pack()
self.pb.pack()
self.pb.start(500)
self.generatebutton.config(state='disabled')
Joke()
Hope that's helpful!
I am just trying to make a non-graphic game in Tkinter but am having trouble with the entry widget. How can I wait for "<Return>" to be pressed before printing something?
from Tkinter import *
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
f = Frame(master, width=500, height=300)
f.pack(fill=X, expand=True)
mt = StringVar()
menubar = Menu(master)
menubar.add_command(label="New Game", command=self.new_game)
menubar.add_command(label="Continue Game", command=self.continue_game)
master.config(menu=menubar)
maintext = Label(master, fg="blue", textvariable=mt)
maintext.pack(side=BOTTOM)
mt.set("")
self.e1 = Entry(master)
self.e1.pack()
self.e1.bind("<Return>")
self.e1.lower()
global mt
def new_game(self):
mt.set("What do you want your username to be?")
self.e1.lift()
#wait for <Return> to be pressed
mt.set("Welcome " + self.e1.get())
def continue_game(self):
mt.set("Type your username in.")
root = Tk()
app = App(root)
root.mainloop()
I want it to be when I click "New Game" on the top menubar, it shows the entry box and waits for me to type something in, and then click enter. THEN it prints out "Welcome"+(what the person types in). What actually happens is when I click New game, it immediately just prints "Welcome".
By print, I mean aet the Label at the bottom to something else, which is reffered to by "mt.set".
In GUI programs you don't wait* for something to happen, you respond to events. So, to call a function when the user presses return you would do something like:
self.e1.bind("<Return>", self._on_return)
The above will call the function _on_return when the user presses the return key.
In your specific code you don't really need a StringVar. For example, you could do this:
def __init__(self, master):
...
self.maintext = Label(master, fg="blue")
...
def _on_return(self, event):
self.maintext.configure(text="Welcome, %s" % self.e1.get())
* strictly speaking, you can wait for things, but that's not the right way to write GUI programs except under specific circumstances, such as waiting for a dialog to be dismissed.