from tkinter import *
master = Tk()
e1 = Entry(master)
us = e1.get() # doesn't work
def factorize(us):
product=1
for x in range(1,us+1): # gives error here
product=product*x
print(product)
Label(master, text="Number").grid(row=0)
e1.grid(row=0, column=1)
e1.get()))
Button(master, text='Quit', command=master.quit).grid(row=3, column=0, sticky=W, pady=4)
Button(master, text='ans', command=factorize).grid(row=3, column=1, sticky=W, pady=4)
mainloop()
Few problems that I see:
-The example code you provided was a mess, that could be due to poor formatting but regardless, I've fixed it for my example.
-You are calling e1.get() once, after creating the Entry. This would return an empty string; however you don't actually do anything with the stored variable anyway so it's useless. us is never used.
-The command = factorize doesn't pass a variable, and factorize requires a variable. I've changed this so that the callback will pass in the Entry widget. In this way, we can call us = int(e1.get()) inside the function, so that every time the button is clicked, we get the newest entry value.
To do this, I changed the command to command = lambda: factorize(e1). lambda essentially declares an 'anonymous function'. It is the only way to pass variables from a callback using Tkinter, because the command keyword expects the name of a function, example command = master.destroy. Speaking of, I also changed master.quit to master.destroy because you most likely want to destroy it.
-I've wrapped us = int(e1.get()) in a try/catch block, because you want an int for your function. Entry.get() will return a string which you can't use to create a range.
-Finally I've imported tkMessageBox so that I can produce a nice error message when you give a bad value to the Entry (example, anything that can't be converted to an integer)
from tkinter import *
import tkMessageBox
master= Tk()
e1 = Entry(master)
def factorize(us):
try:
us = int(e1.get())
except ValueError:
tkMessageBox.showerror("Value Error", "Please enter an integer!")
else:
product=1
for x in range(1,us+1):
product=product*x
print(product)
Label(master, text="Number").grid(row=0)
e1.grid(row=0, column=1)
Button(master, text='Quit', command=master.destroy).grid(row=3, column=0, sticky=W, pady=4)
Button(master, text='ans', command=lambda: factorize(e1)).grid(row=3, column=1, sticky=W, pady=4)
master.mainloop( )
The script will insert the the button then it will get the value which is blank
so you need to move the us to into the function and then remove the us from the parameters this will mean that the value is set when the button is clicked
also you should put some try statement to ensure that the program can handle all inputs
Related
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.
I am working on a relatively large project, but have managed to recreate my problem in just a few lines:
import tkinter as tk
root = tk.Tk()
root.geometry('200x200')
def doStuff():
pass
sv = tk.StringVar()
def callback():
print(E.get())
doStuff()
return True
E = tk.Entry(root, bg="white", fg="black", width=24, textvariable=sv, validate="key",validatecommand=callback)
E.grid(row=0, column=0, padx=30, pady=5, sticky=tk.E)
root.mainloop()
The desired output would be that every time the user changes the entry in this Entrywidget, a function is called.
This works just fine, but using E.get() returns the 'previous' entry, for example:
-entry is 'boo'
-E.get() is 'bo'
Python seems to run Callback() before the Entry Widget has been changed.
Validation by design happens before the text has been inserted or deleted. For validation to work, it must be able to prevent the data from being changed.
If you aren't doing validation, but instead just want to call a function when the value changes, the best way to do that is to put a trace on the associated variable.
def callback(*args):
print(E.get())
doStuff()
return True
sv = tk.StringVar()
sv.trace_add("write", callback)
Hi I'm a beginner in Python and tkinter and I need to use a Button that show me the value in a dictionary according to a key introduced by an user through an Entry. If the introduced key is in the dictionary the value should be shown in a Disabled Entry for the description of the key, and if it is not in the dictionary it should show a message box asking for a different key. I'm using an if-else lambda function in the command of the button but it doesn't seem to be working and I can't figure out why.
I'll put the code I'm using below.
from tkinter import *
from tkinter import messagebox
root=Tk()
dictio={1:"one", 2:"two"}
test=False
textEntry = StringVar()
def show_description(key, dict, text):
if key in dict.keys():
textEntry.set(text)
else:
test=True
code_entry = Entry(root)
code_entry.grid(row=1, column=1, sticky='nsew')
description_entry = Entry(root, state="disabled", textvariable = textEntry)
description_entry.grid(row=0, column=1, sticky='nsew')
show_button = Button(root, text="Mostrar descripción", command=lambda test:show_description(int(code_entry.get()),
dictio,
dictio[int(code_entry.get())]) if (test==False) else messagebox.showinfo("Info", "The number is not in the database"))
show_button.grid(row=0, column=2)
root.mainloop()
The command argument requires a function with no positional arguments, so using lambda x: <do-something> will raise an error. In this case none of the arguments need to be passed during the callback and so you should simplify things to
def show_description():
key = int(code_entry.get())
if key in dictio:
textEntry.set(dictio[key])
else:
messagebox.showinfo("Info", "The number is not in the database")
show_button = Button(root, text="Mostrar descripción", command=show_description)
Also, doing this
dictio[int(code_entry.get())]
the way you did could have raised a KeyError after fixing the lambda having no arguments.
from tkinter import *
from tkinter import messagebox
root=Tk()
dictio={1:"one", 2:"two"}
test=False
textEntry = StringVar()
display=StringVar()
def show_description():
print(display.get()) #==get the value of the stringvat
x=int(display.get()) #==convert the value to integer
if dictio.get(x)==None:
messagebox.showinfo("Info", "The number is not in the database")
else:
textEntry.set(dictio.get(x)) #==get the value of the key from dictio dictionary and set it for description_entry
code_entry = Entry(root,textvariable=display)
display.set("") #==set value as nothing
code_entry.grid(row=1, column=1, sticky='nsew')
description_entry = Entry(root, state="disabled", textvariable = textEntry)
description_entry.grid(row=0, column=1, sticky='nsew')
show_button = Button(root, text="Mostrar descripción", command=show_description)
show_button.grid(row=0, column=2)
root.mainloop()
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()