I have a hard time trying to disable the buttons I don't need in Tkinter, until some condition is met.
The following code it's a reference of what I'm doing:
ID_Personal=[]
ID_Product=[]
from tkinter import *
window = Tk()
def addProduct():
def callback():
ID_Product.append(ID_Product_Entry.get())
print("Product registered")
windowProduct = Tk()
lblProduct = Label(windowProduct, text="ID: ")
lblProduct.grid(padx=10, pady=10, row=0, column=0)
ID_Product_Entry = Entry(windowProduct)
ID_Product_Entry.grid(padx=10, pady=10, row=0, column=1)
btnAdd = Button(windowProduct, text="Submit",command=callback)
btnAdd.grid(padx=10, pady=10, row=1, column=0)
windowProduct.mainloop()
def addPersonal():
def callbackPersonal():
ID_Personal.append(ID_Personal_Entry.get())
print("Employee registered")
windowPersonal = Tk()
lblProduct = Label(windowPersonal, text="ID: ")
lblProduct.grid(padx=10, pady=10, row=0, column=0)
ID_Personal_Entry = Entry(windowPersonal)
ID_Personal_Entry.grid(padx=10, pady=10, row=0, column=1)
btnAddP = Button(windowPersonal, text="Submit",command=callbackPersonal)
btnAddP.grid(padx=10, pady=10, row=1, column=0)
windowPersonal.mainloop()
btnProduct = Button(window,text="Product",command=addProduct)
btnProduct.grid(padx=10, pady=10, row=0, column=0)
btnPersonal = Button(window,text="Personal",command=addPersonal)
btnPersonal.grid(padx=10, pady=10, row=1, column=0)
window.mainloop()
Basically what I need to do is disable the button btnProduct when my ID_Personal list it's empty. Once some personal has been registered, then it must be active again. I've been trying but nothing seems to work. I don't know if I'm using the if condition wrongly or what. Thank you in advance for your help.
You can set the state of btnProduct to "disabled" when you create it, as the list ID_Personal is initially empty.
btnProduct = Button(window,text="Product",command=addProduct,state='disabled')
You can then change the button state to "normal" in the callbackPersonal function using btnProduct.config(state='normal')
This will normalize the button the first time an item is added to ID_Personal
Now if your app demands that the button should go back to "disabled" if ID_Personal is empty and turn "normal" only when ID_Personal is non-empty then the above solution won't work. In that case, we need to recursively update the widgets based on changing conditions. The "after" function can help us to achieve that.
def update():
if len(ID_Personal) > 0:
btnProduct.config(state='normal')
else:
btnProduct.config(state='disable')
window.after(1,update)
update()
Adding the above code to your program will help you update your widgets (button in this case) continuously after every 1 millisecond.
Set the state disabled when you create the button.
btnProduct = Button(window,text="Product",command=addProduct, state="disabled")
And in the callbackPersonal function set the state active.
btnProduct.config(state="active")
This way when you run the program the product button will be disabled, but once you add your first personal, the button will be active.
Related
Using Tkinter and Python. Already created a window for the buttons to be placed on. I want there to be four buttons to appear, and I want to be able to click one of the four buttons, and be able for it to set the selection variable = "whatever I clicked", so that I can then use this variable later to call an API. When I run the program and click on the "General knowledge" button and print the selection, it does correctly print "General knowledge", but then when I try to return this selection variable it just doesn't work and I don't know why.
def select1():
selection = "General Knowledge"
print(selection)
def select2():
selection = "Science"
def select3():
selection = "Entertainment"
def select4():
selection = "Miscellaneous"
button1 = tk.Button(text = "General Knowledge", command = select1)
button1.place(x=100, y=100)
button2 = tk.Button(text = "Science", command = select2)
button2.place(x=100, y=140)
button3 = tk.Button(text = "Entertainment", command = select3)
button3.place(x=100, y=180)
button4 = tk.Button(text = "Miscellaneous", command = select4)
button4.place(x=100, y=220)
There are several ways to accomplish your goal.
One way is to write a single function that will take a value to assign to your variable. This way you can have as many buttons as you like and only a single function.
Not if you are using functions you have to either pass the variable to the function or let the function know it is in the global namespace.
import tkinter as tk
root = tk.Tk()
selection = ''
def assign_value(value):
global selection
selection = value
lbl["text"] = value
print(selection)
lbl = tk.Label(root, text='Selection Goes Here')
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: assign_value("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: assign_value("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: assign_value("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: assign_value("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
Or you can assign the value directly from the button.
import tkinter as tk
root = tk.Tk()
selection = tk.StringVar()
selection.set('Selection Goes Here')
lbl = tk.Label(root, textvariable=selection)
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: selection.set("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: selection.set("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: selection.set("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: selection.set("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
I am sure if I spent more time on this I could think up something else but the idea is basically write your code in a more DRY (Don't Repeat Yourself) fashion and make sure you are assigning the value to the variable in the global namespace or else it will not work as you expect.
My son is trying to learn python and wondered if someone could help on here?
The issue we are having is that we can not get password validation to work. Nothing fancy,
1 st window - enter name and password
if correct - 2nd window pops up
if incorrect - 3 window pops up
We have the following code, however the third window also pops up.
I suspect it's something to do with def main or variable.
from tkinter import*
window1=Tk()
window1.title("First window")
username="user"
password="password"
def main():
if eone == "user" and etwo == "password":
master=tk()
master.title("second window")
else:
master1=tk()
master1.title("third window")
Label(window1, text="username").grid(row=0)
Label(window1, text="password").grid(row=1)
eone=Entry(window1)
etwo=Entry(window1, show='*')
eone.grid(row=0, column=1)
etwo.grid(row=1, column=1)
b1 = Button(window1, text="login") ,bg='00c714',fg='#ffffff',command=main())
b1.grid(row=3, column=0, sticky=E)
b2=Button(window1, command=window1.destroy, text="exit", bg='#fc0303' ,fg='#ffffff')
b2.grid(row=3, column=1, sticky=E)
mainloop()
He has spent many hours on it yesterday and would appreciate any help
Thanks
First, the code you posted gave some errors so fixing them:
replacing tk() with ~~Tk()~~ Toplevel() (see the comments)
replacing '00c714' with '#00c714'
removing parantheses here "login")
now it becomes "compile" time error-free. As for your question, 2 things need changing:
When we need to give a callback / command to a button, we give the function itself and not call it! IOW, command=main() will lead to calling main right away when program runs (without pressing to button). Instead, we should do command=main (note the lack of parantheses). Actually this is what is done here also: command=window1.destroy - we need to give the function itself and tkinter will call it with parantheses when button is pressed.
eone == "user" This compares the tkinter Entry widget directly with the string "user"! What you meant is through get method of entries: eone.get() == "user". Same goes for etwo too.
Overall, here is the code with these modifications (and some PEP-8 compliant formatting):
from tkinter import*
window1 = Tk()
window1.title("First window")
username = "user"
password = "password"
def main():
# Change here: using `get` to get what is written in entries
if eone.get() == "user" and etwo.get() == "password":
master = Toplevel()
master.title("second window")
else:
master1 = Toplevel()
master1.title("third window")
Label(window1, text="username").grid(row=0)
Label(window1, text="password").grid(row=1)
eone = Entry(window1)
etwo = Entry(window1, show='*')
eone.grid(row=0, column=1)
etwo.grid(row=1, column=1)
# Change here: using function `main` itself instead of calling it
b1 = Button(window1, text="login", bg="#00c714", fg="#ffffff", command=main)
b1.grid(row=3, column=0, sticky=E)
b2 = Button(window1, command=window1.destroy, text="exit", bg="#fc0303", fg='#ffffff')
b2.grid(row=3, column=1, sticky=E)
mainloop()
I am attempting to construct a simple game using the Tkinter GUI. The first portion of the game is asking if one wants to play. My Tkinter looks as follows:
window = tk.Tk()
window.rowconfigure(0, minsize=50, weight=1)
window.columnconfigure([0, 1, 2], minsize=50, weight=1)
lbl_value = tk.Label(master=window, text="Welcome!")
lbl_value.grid(row=0, column=1)
lbl_value = tk.Label(master=window, text="Would you like to play?")
lbl_value.grid(row=1, column=1)
btn_yes = tk.Button(master=window, text="Yes", command=window.destroy)
btn_yes.grid(row=2, column=0, sticky="nsew")
btn_no = tk.Button(master=window, text="No", command=**??**)
btn_no.grid(row=2, column=2, sticky="nsew")
window.mainloop()
The "Yes" button is operating as intended, and continuing with the rest of the code. The "No" button however, I am not sure how to get it to exit the the running of the program all together (not just the window), or even better, how to get it to open an additional window stating "Maybe next time", then ending the program when that window is exited out of.
Create a new function where you can define a new tkinter screen which will appear when user press NO button See
def no_button_function(): # function that will be called when user pressed no button
new_window = tk.Toplevel(window)
new_window.title('See You Next Time')
# create the good bye message using labels and buttons accordingly
and now pass this function to NO buttton
btn_no = tk.Button(master=window, text="No", command=no_button_function)
btn_no.grid(row=2, column=2, sticky="nsew")
Hope You Got This.
Tick Mark If Satisfied
I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()
I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()