Tkinter update label with variable from inside function - python

I'm using Tkinter to create a window with an entry field and a button. When the button is pressed and a certain condition is not met, I need my_label2 to show a specific text, in this case 'Not Valid'. Otherwise, I need the my_label2 to be blank. I have the variable label_text inside a function that is called by the button press, but I get an error saying that label_text is not defined. Can someone help me out with this?
root = tk.Tk()
def my_function():
valid = #this variable is either true or false
if valid :
label_text = ''
else :
label_text = 'Not Valid'
my_label = tk.Label(root, text = "Enter text: ")
my_label.grid(row = 0, column = 0)
my_entry = tk.Entry(root)
my_entry.grid(row = 0, column = 1)
my_button = tk.Button(root, text = "Submit", command = my_function)
my_button.grid(row = 1, column = 1)
my_label2 = tk.Label(root, textvariable = label_text)
my_label2.grid(row = 2, column = 1)
root.mainloop()

Tkinter Variables are different from normal variables. To create one:
label_text = tk.StringVar()
Then, rather than assigning to the variable, you nee to use the set method:
label_text.set('')
or
label_text.set('Not Valid')
See: http://effbot.org/tkinterbook/variable.htm

Related

Problem with Tkinter using StringVar(), trace() and Entry()

I am defining a StringVar() and giving it a value, then using it as the textvariable of an Entry widget. I have also added a trace to the StringVar so that I can use it as a placeholder checker and make the placeholder a different colour to the typed text.
However, when I run the code the entry widget contains no text, but if I print the value of the StringVar() it gives the correct value. Also, the trace command is never called and when I print the value of the textvariable of the Entry widget, it comes out as PY_VAR#.
Does anyone know why this is not working and how to solve it?
circleVarEmailAddress = StringVar()
circleVarEmailAddress.set("email address")
circletextEmailAddress = Entry(forgottenWindow, textvariable = circleVarEmailAddress,
font = 10, relief = "raised", highlightbackground = "black",
borderwidth = 2, fg = "#808080")
circletextEmailAddress.place(x = 75, y = 100, width = 250, height = 50)
def placeholderEmailAddress(a, b, c):
print("Hey")
for i in range(1, 13):
if("email address"[:i] in circleVarEmailAddress.get() == True and
"email address"[i:] in circleVarEmailAddress.get() == True):
index1 = circleVarEmailAddress.get().index("email address"[:i])
index2 = circleVarEmailAddress.get().index("email address"[i:])
circleVarEmailAddress.set(circleVarEmailAddress.get()[:index1] +
circleVarEmailAddress.get()[index1 + i:index2] +
circleVarEmailAddress.get()[index2 + 13 - i:])
if(circleVarEmailAddress.get() != "email address" and
"email address" in circleVarEmailAddress.get() == True):
circleVarEmailAddress.set(circleVarEmailAddress.get().replace("email address", ""))
if circleVarEmailAddress.get() == "":
circleVarEmailAddress.set("email address")
if circleVarEmailAddress.get() == "email address":
circletextEmailAddress.config(fg = "#808080")
else:
circletextEmailAddress.config(fg = "#000000")
circleVarEmailAddress.trace_add("write", placeholderEmailAddress)
Your code runs fine for me if I add some boilerplate.
I assume from the variable name "forgottenWindow" that this is a new window in your program. The problem you are seeing can happen if you use Tk() to make additional windows. Always use Toplevel to make new windows beyond your first one.
forgottenWindow = Toplevel()

How can I make my button in Python Tkinter clickable?

I'm trying to create a feedback form using Tkinter in Python. For now I am writing for it to show a message box if the name entry is '' when clicked on the submit button. But the button cannot be clicked and is disabled. How can I fix this?
# import all functions from the tkinter
from tkinter import *
from tkinter import messagebox
# import messagebox class from tkinter
from tkinter import messagebox
# Create a GUI window
root = Tk()
# create a function to check input
def check_input():
if name_input == '':
messagebox.showerror("please enter your name")
# create the input entry
name_input = Entry(root)
age_input = Entry(root)
phone_input = Entry(root)
email_input = Entry(root)
# label the input entry
name_label = Label(text="Username")
age_label = Label(text="Age")
phone_label = Label(text="Phone")
email_label = Label(text="Email")
# display the input entry
name_label.grid(row = 1,column = 1, padx = 10)
name_input.grid(row = 2,column = 1,padx = 10)
age_label.grid(row = 3,column = 1,padx = 10)
age_input.grid(row = 4,column = 1,padx = 10)
phone_label.grid(row = 5,column = 1,padx = 10)
phone_input.grid(row = 6,column = 1,padx = 10)
email_label.grid(row = 7,column = 1,padx = 10)
email_input.grid(row = 8,column = 1,padx = 10)
# create the submit button
submit_button = Button(root,text="Submit",command = check_input)
# display the submit button
submit_button.grid(row = 9,column = 1,padx = 10)
# Start the GUI
root.mainloop()
You have to use the get() method to get contents from an Entry:
# create a function to check input
def check_input():
if name_input.get() == '':
messagebox.showerror("please enter your name")
[![tested and shows no error][1]][1]
your button is clickable and is visible ... there maybe some other issue with your requirements but button works
[1]: https://i.stack.imgur.com/JQqH3.png
if you want to get value from the textbox your need to set text variable for entry
like
ttk.Entry(win,textvariable=hexanum).grid(column=1,row=0)
then if you need to get values from text box you'll be doing something like
inhexa=(hexanum.get()) #hexanum is the textvariable associated to entry/textbox
#inhexa is a variable in which the value from get function is stored (if need to store)
do your homework :) feel free to ask

Tkinter Entry returns blank when called from another script but works fine by its self

The is going to work like this:
Launcher with buttons to run different functions on other scripts. However when I try launching the "New Account" a new window pops up as it should but the entry field prints blank.
Launcher:
import Setup as s
import Stock as t
from tkinter import *
import os
root = Tk()
root.title("SWM Launcher")
welcome = Label(root, text = "Welcome to the Stock and Wastage Manager Launcher")
welcome.grid(row = 0, column =1, columnspan =3)
l1 = Label (root, text = "Please choose from the options below")
l1.grid(row = 1, column =1, columnspan =3)
submit = Button(root, text = "Open Account", command = lambda: program())
submit.grid(row = 3, column =1)
submit = Button(root, text = "New Account", command = lambda: s.setep())
submit.grid(row = 3, column =2)
What I'm trying to get to work from the setup script
class App:
def __init__(self, window):
window.title("SWM Account Maker")
window.config(bg = "grey")
window.geometry("800x900")
self.searched = StringVar()
name = Entry(window, width = 50, borderwidth = 5,textvariable=self.searched).grid(row = 2, column =1, columnspan =3)
submit = Button(window, text = "Submit", command = lambda: self.name()).grid(row = 3, column =2)
def name (self):
works = self.searched.get()
print(works)
def setep():
root = Tk()
app = App(root)
root.mainloop()
The output i get from the print statement is blank yet if I run setup separately it works fine.I feel like I have miss understood something and no solution's I have found online work. also its my first project working with classes and Tkinter.
It is because you have used multiple instances of Tk(). Either change Tk() to Toplevel() inside setep() function or change self.searched = StringVar() to self.searched = StringVar(window) inside App.init()

Random tkinter window opening on if/else statement

I'm wondering if I got my if else statement wrong or if its a tkinter issue. I want it so that if a 0 is left in any or all boxes, it gives an error message. But after the error message is closed, it opens a random blank window. This is my code. The specific area is the if else statement within the function valueget()
import tkinter as tk
def mainwindow():
mainwindow = tk.Tk()
mainwindow.title('Enter values')
mainwindow.geometry('160x110')
mainwindow.config(bg='#aaf0d1')
tk.Label(mainwindow, text = 'Enter a', font = ('verdana'), bg='#aaf0d1').grid(row=0)
tk.Label(mainwindow, text = 'Enter b', font = ('verdana'), bg='#aaf0d1').grid(row=1)
tk.Label(mainwindow, text = 'Enter c', font = ('verdana'), bg='#aaf0d1').grid(row=2)
getA = tk.IntVar()
aBox = tk.Entry(mainwindow, textvariable = getA, width=3, bg='#aaf0d1')
aBox.grid(row=0, column=1)
aBox.config(highlightbackground='#aaf0d1')
getB = tk.IntVar()
bBox = tk.Entry(mainwindow, textvariable = getB, width=3, bg='#aaf0d1')
bBox.grid(row=1, column=1)
bBox.config(highlightbackground='#aaf0d1')
getC = tk.IntVar()
cBox = tk.Entry(mainwindow, textvariable = getC, width=3, bg='#aaf0d1')
cBox.grid(row=2, column=1)
cBox.config(highlightbackground='#aaf0d1')
button = tk.Button(mainwindow, text='Obtain roots', command = lambda: valueget(), font = ('verdana'), highlightbackground='#aaf0d1')
button.grid(row=4)
button.config(bg='#aaf0d1')
def valueget():
readA = getA.get()
readB = getB.get()
readC = getC.get()
intA = int(readA)
intB = int(readB)
intC = int(readC)
negroot = (readB**2)-(4*readA*readC)
quadformulaplus = (-readB + (pow(negroot,0.5)))/(2*readA) #quad forumla
quadformulaminus = (-readB - (pow(negroot,0.5)))/(2*readA) #quad forumla
messagewindow = tk.Tk()
messagewindow.geometry('290x50')
messagewindow.title('Roots of the equation')
messagewindow.config(bg='#aaf0d1')
if readA == 0 or readB==0 or readC==0 or (readA==0 and readB==0 and readC==0):
errorwindow = tk.messagebox.showerror(message='none').pack()
else:
label = tk.Label(messagewindow, text = f'The roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}', bg='#aaf0d1', font = ('verdana'))
label.grid(row=1)
closebutton = tk.Button(messagewindow, text='Close', command = lambda: messagewindow.destroy(), font = ('verdana'), highlightbackground='#aaf0d1')
closebutton.grid(row=2)
closebutton.config(bg='#aaf0d1')
messagewindow.mainloop()
# print(f'the roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}')
mainwindow.mainloop()
def startup():
startpage = tk.Tk()
startpage.title('Solver')
photo = tk.PhotoImage(file = r"/Users/isa/Desktop/DiffEqns/cover.png") #image load
coverbutton = tk.Button(startpage, image = photo, command = lambda: [startpage.destroy(), mainwindow()])
coverbutton.pack()
coverbutton.configure(highlightbackground='#aaf0d1')
startpage.mainloop()
startup()
Here's a basic idea of what I would do:
import tkinter as tk
from tkinter import messagebox
def mainwindow(root):
# Creates a toplevel window
mainwindow = tk.Toplevel()
mainwindow.protocol("WM_DELETE_WINDOW", root.destroy) # This overrides the "X" being clicked to also destroy the root window.
root.withdraw() # "Hides" the root window, leaving it (and mainloop) running in the background.
mainwindow.title('Enter values')
mainwindow.geometry('160x110')
mainwindow.config(bg='#aaf0d1')
# Since all three of the labels/entries are the same
# we can save space by generating them in a loop
entry_items = ('Enter a', 'Enter b', 'Enter c')
values = []
for x, item in enumerate(entry_items): # Using enumerate and x to assign rows
tk.Label(mainwindow, text = item,
font = ('verdana'), bg='#aaf0d1').grid(row=x) # Row assigned to x.
values.append(tk.StringVar()) # Appended StringVar to list.
tk.Entry(mainwindow,
textvariable = values[-1], # Uses the last value appended to the values list.
highlightbackground='#aaf0d1',
width=3,
bg='#aaf0d1').grid(row=x, column=1) # Row assigned to x.
tk.Button(mainwindow,
text='Obtain roots',
command = lambda vals = values: valueget(vals), # Here the button command is assigned with the values list
font = ('verdana'), bg='#aaf0d1',
highlightbackground='#aaf0d1').grid(row=3) # we know there are 3 items before this.
mainwindow.lift() # This is a method of bringing a window to the front
def valueget(vals):
# This line gets the values from the StringVars, converts them to ints,
# and returns them to their respective variables.
try:
readA, readB, readC = [int(val.get()) for val in vals]
except ValueError:
messagebox.showerror(title="Number Error", message='Values must be numbers')
return
# Here the variables are checked to see if they are 0
# Since each one is being checked if it is 0, there is no need to check if they are all 0.
for val in (readA, readB, readC):
if val == 0:
# If they are 0, shows an error message
messagebox.showerror(title="Zero Error", message='Values must not be zero')
return
# Creates a toplevel to display the results
messagewindow = tk.Toplevel()
messagewindow.title('Roots of the equation')
messagewindow.config(bg='#aaf0d1')
negroot = (readB**2)-(4*readA*readC)
quadformulaplus = (-readB + (pow(negroot,0.5)))/(2*readA) #quad forumla
quadformulaminus = (-readB - (pow(negroot,0.5)))/(2*readA) #quad forumla
tk.Label(messagewindow,
text = f'The roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}',
bg='#aaf0d1',
font = ('verdana')).pack(padx = 5, pady = 2)
tk.Button(messagewindow,
text='Close',
command = messagewindow.destroy, # There is no need for a lambda for this.
font = ('verdana'),
bg = '#aaf0d1',
highlightbackground='#aaf0d1').pack(padx = 5, pady = 2)
# print(f'the roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}')
messagewindow.lift() # This is a method of bringing a window to the front
def startup():
startpage = tk.Tk()
startpage.title('Solver')
# COMMENTED OUT FOR TESTING
#photo = tk.PhotoImage(file = r"/Users/isa/Desktop/DiffEqns/cover.png") #image load
coverbutton = tk.Button(startpage,
# COMMENTED OUT FOR TESTING
#image = photo,
text = "TESTING", # HERE FOR TESTING
highlightbackground='#aaf0d1',
command = lambda root = startpage: mainwindow(root)).pack() # Passes the startpage to the mainwindow function.
startpage.mainloop() # The only mainloop you need.
startup()
I would recommend to improve the readability of the if-else statement for a start.
coefficients = [readA, readB, readC]
if sum(coefficients): # If they all are all zeros this will be False
if min(coefficients): # If any one is zero, this will be False
label = tk.Label(messagewindow, text = f'The roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}', bg='#aaf0d1', font = ('verdana'))
label.grid(row=1)
closebutton = tk.Button(messagewindow, text='Close', command = lambda: messagewindow.destroy(), font = ('verdana'), highlightbackground='#aaf0d1')
closebutton.grid(row=2)
closebutton.config(bg='#aaf0d1')
else:
errorwindow = tk.messagebox.showerror(message='none').pack()
else:
errorwindow = tk.messagebox.showerror(message='none').pack()

tkinter: dynamically create and delete entry

I am using tkinter to create a small GUI for some Python scripts. For this GUI I need a Combobox named combo with three options:
"none" (the user wants to hand in no data)
"constant" (the user wants to hand in only one value)
"adjustable" (the user wants to hand in more than one value)
Depending on the choice done in combo, a different number of entrys should
appear. The first option should show no entry (and delete all "leftover"
entrys), the second one should show only one entry and the third one should show
two entrys. For me it's no problem to create these entrys but I don't know how
to make them disappear. Once they were created they stay until the GUI is
closed.
I tried something like this:
import tkinter as tk
master = tk.Tk()
var1 = tk.StringVar()
var2 = tk.StringVar()
def submit():
if choice.get() == "none": # all entry boxes schould disappear
entry1.destroy()
entry2.destroy()
if choice.get() == "constant": # only 1 entry box schould be visible
entry1 = tk.Entry(master, textvariable = var1)
entry1.grid(column = 0, row = 1)
entry2.destroy()
if choice.get() == "adjustable": # all entry boxes should be visible
entry1 = tk.Entry(master, textvariable = var1)
entry1.grid(column = 0, row = 1)
entry2 = tk.Entry(master, textvariable = var1)
entry2.grid(column = 0, row = 2)
choice = tk.StringVar(value = "none")
combo = ttk.Combobox(master, textvariable = choice, state = "readonly")
combo["values"] = ("none", "constant", "adjustable")
combo.grid(column = 0, row = 0)
action = tk.Button(master, text = "confirm", command = submit)
action.grid(column=1, row=0)
master.mainloop()
But as I said before, once a entry was created it did not disappear anymore. I
also tried entry.grid_forget() insted of entry.destroy() but this also
didn't work.
I also tryed to declare entry1 and entry1 outside of submit() but then I
don't know how to recreate these entrys once they were destroyed.
Thanks to the help of jasonharper I found a solution while working at another script. The code should look something like this:
import tkinter as tk
from tkinter import ttk
master = tk.Tk()
var1 = tk.StringVar()
var2 = tk.StringVar()
def submit():
if choice.get() == "none": # all entry boxes schould disappear
entry1.grid_remove()
entry2.grid_remove()
if choice.get() == "constant": # only 1 entry box schould be visible
entry1.grid(column = 0, row = 1)
entry2.grid_remove()
if choice.get() == "adjustable": # all entry boxes should be visible
entry1.grid(column = 0, row = 1)
entry2.grid(column = 0, row = 2)
choice = tk.StringVar(value = "none")
combo = ttk.Combobox(master, textvariable = choice, state = "readonly")
combo["values"] = ("none", "constant", "adjustable")
combo.grid(column = 0, row = 0)
entry1 = tk.Entry(master, textvariable = var1)
entry2 = tk.Entry(master, textvariable = var2)
action = tk.Button(master, text = "confirm", command = submit)
action.grid(column=1, row=0)
master.mainloop()
Now all entrys are deleted or created when wanted. To delete the text at the entrys You only have to add entry.delete(0,"end").
I hope this will also help others.

Categories