tkinter: dynamically create and delete entry - python

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.

Related

How to enable a disabled Button after filling Entry widgets?

I have 2 Entrys and one button. I want to make that button's state disabled until the two Entrys are filled in. How can I achieve that?
howManyStocksLabel = Label(root, text = "How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row = 1, column = 0)
howManyStocksEntry = Entry(root, borderwidth = 3)
howManyStocksEntry.grid(row = 1, column = 1)
riskLabel = Label(root, text = "Enter risk %")
riskLabel.grid(row = 2, column = 0, sticky = 'w')
riskEntry = Entry(root, borderwidth = 3)
riskEntry.grid(row = 2, column = 1)
nextButton = Button(root, text = "Next!", width = 20, height = 2,state = DISABLED,
fg = 'green', bg = 'white',
command= lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row = 4, column = 1)
I tried to check whether the entries are filled in or not by:
if(riskEntry.get() != ""):
....................
but it just doesn't work.
You need to check if the value is there after the user inputs it. Also, you can use tk.StringVar() as a text variable and trace it.
Here is an example:
import tkinter as tk
def check_entry(*args):
if r1.get() and r2.get():
b1.config(state='normal')
else:
b1.config(state='disabled')
root = tk.Tk()
r1 = tk.StringVar(master=root)
r2 = tk.StringVar(master=root)
e1 = tk.Entry(root, textvariable=r1)
e1.pack()
e2 = tk.Entry(root, textvariable=r2)
e2.pack()
b1 = tk.Button(root, text='Click Me!', state='disabled')
b1.pack()
r1.trace('w', check_entry)
r2.trace('w', check_entry)
root.mainloop()
You will need to use a binding on your entry widgets to check whether the user has entered anything into the entry or not.
This code will fire the check_entry function every time the user types in one of the entry boxes:
riskEntry.bind('<KeyRelease>', check_entry)
howManyStocksEntry.bind('<KeyRelease>', check_entry)
Then your check_entry function might look like this:
def check_entry(event): #event is required for all functions that use a binding
if riskEntry.get() and howManyStocksEntry.get():
nextButton.config(state=NORMAL)
else:
nextButton.config(state=DISABLED)
One way to do it would be to utilize the ability to "validate" their contents that Entry widgets support — see adding validation to an Entry widget — but make it check the contents of multiple Entry widgets and change the state of a Button accordingly.
Below shows how to do this via a helper class that encapsulates most of the messy details needed to make doing it relatively painless. Any number of Entry widgets can be "watched", so it scales well to handle forms consisting of many more than merely two entries.
from functools import partial
import tkinter as tk
from tkinter.constants import *
class ButtonEnabler:
""" Enable/disable a Button depending on whether all specified Entry widgets
are non-empty (i.e. contain at least one character).
"""
def __init__(self, button, *entries):
self.button = button
self.entries = entries
for entry in self.entries:
func = root.register(partial(self.check_entries, entry))
entry.config(validate="key", validatecommand=(func, '%P'))
def check_entries(self, this_entry, new_value):
other_entries = (entry for entry in self.entries if entry is not this_entry)
all_others_filled = all(entry.get() for entry in other_entries)
combined = bool(new_value) and all_others_filled
self.button.config(state=NORMAL if combined else DISABLED)
return True
root = tk.Tk()
howManyStocksLabel = tk.Label(root, text="How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row=1, column=0)
howManyStocksEntry = tk.Entry(root, borderwidth=3)
howManyStocksEntry.grid(row=1, column=1)
riskLabel = tk.Label(root, text="Enter risk %")
riskLabel.grid(row=2, column=0, sticky='w')
riskEntry = tk.Entry(root, borderwidth=3)
riskEntry.grid(row=2, column=1)
nextButton = tk.Button(root, text="Next!", width=20, height=2, state=DISABLED,
fg='green', bg='white', disabledforeground='light grey',
command=lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row=4, column=1)
enabler = ButtonEnabler(nextButton, howManyStocksEntry, riskEntry)
root.mainloop()

save entry values for next programmstart tkinter

thanks a lot for your time. I'm currently stuck at the following point: I have developed a GUI with Tkinter with about 200 entries. (For simplification I have only included a small section below). But these 200 entries are seldom filled in at once. Normally 50 entries are filled in every start of the program. When the program is closed, these filled in values are deleted and have to be filled in again after the program is started again. Is there a way to prevent this?
I do not want to lose the values entered in jobNameA_entry and jobNameB_entry when closing the program.
Many thanks in any case.
import tkinter as tk
class Win1:
def __init__(self, master):
self.master = master
self.master.title("Gap Assessment")
self.topFrame = tk.Frame(self.master)
self.topFrame.grid(row=0, column=0, sticky='news', ipady = 5)
self.A_GapFrame = tk.Frame(self.master)
self.B_GapFrame = tk.Frame(self.master)
self.subframe_AGap()
self.subframe_BGap()
# Create a Tkinter variable
self.gapType = tk.StringVar(self.master)
# Dictionary with optionsverschwinden
self.choiceGap = ['AFrame','BFrame']
# self.choiceGap = sorted(self.choiceGap)
self.gapType.set('') # set the default option
self.ctngMenu = tk.OptionMenu(self.topFrame, self.gapType, *self.choiceGap, command=self.chioseGap_handle)
self.ctngMenu.grid(row = 1, column =2)
def chioseGap_handle(self, selected):
if selected == 'AFrame':
self.A_GapFrame.tkraise()
# self.subframe_AGap()
self.A_GapFrame.place(x=20, y=30, width = 210)
self.B_GapFrame.place_forget()
if selected == 'BFrame':
self.B_GapFrame.tkraise()
# self.subframe_BGap()
self.B_GapFrame.place(x=30, y=70, width = 210)
self.A_GapFrame.place_forget()
def subframe_AGap(self):
self.jobNameA_text = tk.StringVar()
self.jobNameA_entry = tk.Entry(self.A_GapFrame, textvariable = self.jobNameA_text)
self.jobNameA_entry.grid(row=1, column=0, sticky='news')
self.jobNameA_text = tk.StringVar()
self.jobNameA_entry = tk.Entry(self.A_GapFrame, textvariable = self.jobNameA_text)
def subframe_BGap(self):
self.jobNameB_text = tk.StringVar()
self.jobNameB_entry = tk.Entry(self.B_GapFrame, textvariable = self.jobNameB_text)
self.jobNameB_entry.grid(row=2, column=0, sticky='news')
self.jobNameB_text = tk.StringVar()
self.jobNameB_entry = tk.Entry(self.B_GapFrame, textvariable = self.jobNameB_text)
root = tk.Tk()
root.geometry("200x300+50+50")
app = Win1(root)
root.mainloop()

Tkinter update label with variable from inside function

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

How can I dynamically create ttk widgets depending on the value entered in a ttk.entry box?

I am trying to make a GUI where as soon as the user inputs an integer into a ttk.entry field, that many checkbuttons need to appear below it. For example, if they put "5" into the entry widget, 5 check buttons need to appear below the entry field.
Edit:
What I ended up using:
self.number_of_stages = tk.IntVar()
self.check_box_dict={}
self.num_of_stages={}
self.stagetempvar={}
self.equipment_widgets={}
def centrifugal_compressor_widgets(self):
self.equipment_widgets.clear()
self.equipment_widgets["NumOfStagesLabelCentComp"]=tk.Label(self.parent, text="Number of Stages:", bg="white")
self.equipment_widgets["NumOfStagesLabelCentComp"].place(relx=0.5, y=260, anchor="center")
self.equipment_widgets["NumOfStagesEntryCentComp"]=ttk.Entry(self.parent, textvariable=self.number_of_stages)
self.equipment_widgets["NumOfStagesEntryCentComp"].place(relx=0.5, y=290, anchor="center")
def OnTraceCentComp(self, varname, elementname, mode):
for key in self.check_box_dict:
self.check_box_dict[key].destroy()
try:
if self.number_of_stages.get() <=15 :
i=1
self.stagetempvar.clear()
while i <= self.number_of_stages.get():
self.stagetempvar[i]=tk.StringVar()
self.stagetempvar[i].set("Closed")
self.check_box_dict[i]=ttk.Checkbutton(self.parent, text=i, offvalue="Closed", onvalue="Open",variable=self.stagetempvar[i])
self.check_box_dict[i].place(relx=(i*(1/(self.number_of_stages.get()+1))), y=360, anchor="center")
i+=1
except:
pass
take a look at the below and let me know what you think...
A very ugly, super basic example:
from Tkinter import *
root = Tk()
root.geometry('200x200')
root.grid_rowconfigure(0, weight = 1)
root.grid_columnconfigure(0, weight = 1)
win1 = Frame(root, bg= 'blue')
win1.grid(row=0, column=0, sticky='news')
number = IntVar()
entry = Entry(win1, textvariable = number)
entry.pack()
confirm = Button(win1, text = 'Press to create widgets...', command = lambda:create_widgets(number.get()))
confirm.pack()
def create_widgets(number):
for n in range(0,number):
Checkbutton(win1, text = 'Checkbutton number : %s' % n).pack()
root.mainloop()

Need assistance Tkinter in Python 2.7

I am writing a subnetting program in Python and I have come across a problem.
So far everything is working minus one thing. I dont know how to change a label in a method. in the code below, SubnetM is the variable being used to show the subnet mask. It is set to 0 by default but when you select HOSTS and enter 6 as Quantity. The 0 does not change to 255.255.255.248. PLEASE HELP
from Tkinter import *
SubnetM = 0
def beenclicked():
radioValue = relStatus.get()
return
def changeLabel():
if radio1 == 'HOSTS':
if Quantity == 6:
SubnetM = "255.255.255.248"
return
app = Tk()
app.title("SUBNET MASK CALCULATOR")
app.geometry('400x450+200+200')
labelText = StringVar()
labelText.set("WELCOME!")
label1 = Label(app,textvariable=labelText, height=4)
label1.pack()
relStatus = StringVar()
relStatus.set(None)
radio1 = Radiobutton(app, text="HOSTS", value="HOSTS", variable=relStatus, command=beenclicked).pack()
radio1 = Radiobutton(app, text="NETWORKS", value="NETWORKS", variable=relStatus, command=beenclicked).pack()
label2Text = StringVar()
label2Text.set("~Quantity~")
label2 = Label(app, textvariable=label2Text, height=4)
label2.pack()
custname = IntVar(None)
Quantity = Entry(app,textvariable=custname)
Quantity.pack()
label3Text = StringVar()
label3Text.set("Your Subnet Mask is...")
label3 = Label(app, textvariable=label3Text, height=4)
label3.pack()
label4Text = StringVar()
label4Text.set(SubnetM)
label4 = Label(app, textvariable=label4Text, height=4)
label4.pack()
button1 = Button(app, text="GO!", width=20, command=changeLabel)
button1.pack(padx=15, pady=15)
app.mainloop()
To fix your problem, make changeLabel like this:
def changeLabel():
# Get the radiobutton's StringVar and see if it equals "HOSTS"
if relStatus.get() == 'HOSTS':
# Get the entrybox's IntVar and see if it equals 6
if custname.get() == 6:
# Set the label's StringVar to "255.255.255.248"
label4Text.set("255.255.255.248")
Also, the .pack method of a Tkinter widget returns None. So, you should make the part that defines the radiobuttons like this:
radio1 = Radiobutton(app, text="HOSTS", value="HOSTS", variable=relStatus, command=beenclicked)
radio1.pack()
radio2 = Radiobutton(app, text="NETWORKS", value="NETWORKS", variable=relStatus, command=beenclicked)
radio2.pack()

Categories