Remove multiple label from tkinter - python

I'm trying to make a simple tkinter script that creates 10 numbers in the GUI after clicking a button. The problem is removing the numbers from the GUI. I can only remove one number. The numbers is beeing created via a loop.
I've printed out the name of the .pack() variable "self.label_a2" and the names are: .!label2, .!label3 and so on. I have not figured out how I can use the ".!label2" names to remove the lables. Nor How to remove more than just one lable.
Here is the code:
from tkinter import *
root = Tk()
class the_GUI:
def __init__(self, master):
self.master = master
master.title("Numbers")
self.start_prim_button = Button(master, text="Get numbers", command=self.main_prim, width=30)
self.start_prim_button.pack()
self.start_secu_button = Button(master, text="Remove numbers", command=self.main_secu, width=30)
self.start_secu_button.pack()
def main_prim(self):
self.label_a1 = Label(text='Numbers:', bg = "orange", width=30)
self.label_a1.pack()
numbers(self)
def main_secu(self):
remove_numbers(self)
def numbers(self):
print('Printing numbers:')
# Loop to create numbers
for i in range(10):
print(i)
self.label_a2 = Label(text=i, bg = "light green", width=30)
self.label_a2.pack()
print(self.label_a2)
def remove_numbers(self):
print('Removing numbers:')
try:
for i in range(10):
self.label_a2.destroy()
root.update_idletasks()
print('Removing', i)
except:
print('Generate numbers first')
my_gui = the_GUI(root)
root.mainloop()
When running the script it's only lable whit number 9 that gets removed. How to make all of the labes go away? Help please.
BR BaconFlip

You can add all the label instances to a list and then iterate through it while destroying them, your final code should look something like this
from tkinter import *
root = Tk()
class the_GUI:
def __init__(self, master):
self.master = master
master.title("Numbers")
self.start_prim_button = Button(master, text="Get numbers", command=self.main_prim, width=30)
self.start_prim_button.pack()
self.start_secu_button = Button(master, text="Remove numbers", command=self.main_secu, width=30)
self.start_secu_button.pack()
self.label_list=[]
def main_prim(self):
self.label_a1 = Label(text='Numbers:', bg = "orange", width=30)
self.label_a1.pack()
numbers(self)
def main_secu(self):
remove_numbers(self)
def numbers(self):
print('Printing numbers:')
# Loop to create numbers
for i in range(10):
print(i)
self.label_a2 = Label(text=i, bg = "light green", width=30)
self.label_a2.pack()
self.label_list.append(self.label_a2)
print(self.label_a2)
def remove_numbers(self):
print('Removing numbers:')
try:
for i in range(10):
self.label_list[i].destroy()
root.update_idletasks()
print('Removing', i)
self.label_a1.destroy()
self.label_list=[]
except:
print('Generate numbers first')
my_gui = the_GUI(root)
root.mainloop()

Another way of doing it is by using root.winfo_children() to get the children of the root widget and checking if the child is an instance of the label using isinstance(). This might be suitable for you if you don't want to store every label in lists.
def remove_numbers(self):
print('Removing numbers:')
try:
for i in self.master.winfo_children():
if isinstance(i, Label):
i.destroy()
root.update_idletasks()
print('Removing', i)
except:
print('Generate numbers first')

Related

Retrieve input from Entry widget stored as an instance variable and use it outside of the class

I have difficulties trying to get the input from Entry widget stored as a instance variable, so I can use it as input outside this class:
class CreateGUI:
def __init__(self, master):
self.master = master
self.master.geometry("275x325")
self.master.columnconfigure(0, weight=1)
self.master.columnconfigure(1, weight=2)
self.checkbutton_var1 = IntVar()
self.checkbutton_var2 = IntVar()
self.path = ''
self.type = []
def add_labels(self):
Label(self.master, text="Provide path to file:").grid(column=0, row=0, padx=10, pady=10, sticky="N")
def add_entries(self):
user_input = Entry(self.master)
user_input.grid(column=0, row=1, padx=5, pady=5, ipadx=60)
return user_input
def add_buttons(self, user_input):
checkbutton1 = Checkbutton(self.master, text="test1", variable=self.checkbutton_var1, onvalue=1,offvalue=0,height=2,width=10)
checkbutton1.grid(column=1, row=0)
checkbutton2 = Checkbutton(self.master, text="test2", variable=self.checkbutton_var2, onvalue=1, offvalue=0,height=2, width=10)
checkbutton2.grid(column=1, row=1)
button = Button(self.master, text="push", bg="pink", bd=100, fg="white",
command=lambda: self.retrieve_input(user_input.get(), self.checkbutton_var1.get(), self.checkbutton_var2.get()))
button.grid(column=0, row=3, padx=20, pady=20, sticky="NEWS")
def retrieve_input(self, p, *args):
self.path = p
#print(self.path)
for el in args:
self.type.append(el)
#print(self.type)
def main():
tk = Tk()
app = CreateGUI(tk)
app.add_labels()
user_input = app.add_entries()
app.add_buttons(user_input)
print(app.type)
print(app.path)
tk.mainloop()
When I start the program, write the input and press the button, it does not print anything. There are empty brackets printed the moment the program is initiated. The prints inside the retrieve_input are printing exactly what I need, but I need this inputs outside of the class, because they will be an input to another class.
I tried everything related to this problem, but it is not working and I would really appriciate any kind of help. Thanks!
You are getting the input for the Entry widget right before anyone can have a chance to type in it. As a result, user_input.get() will return an empty string. One thing you can do is make some sort of trigger for calling add_buttons() that the user activates when they are done filling out user_input. Further tweaking after that should make it work.
Please tell me if you have any more trouble.

Python - Tkinter. Why doesn't my tkinter entry connect to the last variable in the list?

I have a class port which has a name field.
I then have a main window which opens up a form for entering new ports. This form has a button on the first line which when pressed adds a new port to the frame where you can enter the name of the new port etc.
The Entry box's textvariable I've connected to the last port's name in the port-list, however it will not print the correct names when I press the Print button.
If changing the line
MAIN_gui = MAIN_GUI(root)
to
MAIN_interface_pkg(root)
Then it works as I want.
It is the first attempt for me with Python and Tkinter so please have some oversight with bad coding...
#!/usr/bin/env python
import Tkinter as tk
MAIN_VERSION='3.6e'
class Port:
def __init__(self, name, mode, direction):
self.name = tk.StringVar()
self.name.set(name)
self.mode= tk.StringVar()
self.mode.set(mode)
self.direction= tk.StringVar()
self.direction.set(direction)
def quit():
root.destroy()
class MAIN_GUI(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self,parent)
frame = tk.Frame(parent)
frame.pack(expand='0', fill='x')
frame_buttons = tk.Frame(frame, borderwidth='1', relief='groove')
frame_buttons.pack(side=tk.TOP)
frame_quit = tk.Frame(frame, borderwidth='1', relief='groove')
frame_quit.pack(side=tk.TOP)
################
label = tk.Label(frame, text="MAIN Gui version "+MAIN_VERSION)
label.pack(side=tk.TOP)
################
quit_button = tk.Button(frame_quit, text="QUIT", fg="red", command=root.quit)
quit_button.pack(side=tk.TOP)
intf_button = tk.Button(frame_buttons, text="Create Interface Package", command=self.intf_button_action)
intf_button.pack(side=tk.LEFT)
def intf_button_action(self):
global MAIN_interface_pkg_window
if MAIN_interface_pkg_window is None:
MAIN_interface_pkg_window = tk.Tk()
MAIN_interface_pkg = MAIN_INTERFACE_PKG(MAIN_interface_pkg_window)
else:
MAIN_interface_pkg_window.update()
MAIN_interface_pkg_window.deiconify()
class MAIN_INTERFACE_PKG(tk.Frame):
def __init__(self, parent):
self.ports = []
self.main_frame = tk.Frame(parent)
self.main_frame.pack()
self.frame_button = tk.Frame(self.main_frame)
self.frame_button.pack(side=tk.BOTTOM)
self.print_button = tk.Button(self.frame_button, text="Print", fg="blue", command=self._dbg)
self.print_button.pack(side=tk.TOP)
self.frame_three = tk.Frame(self.main_frame, borderwidth=3, relief="groove")
self.frame_three.pack(side=tk.TOP)
self._addport(self.frame_three)
def _dbg(self):
for port in self.ports:
print("DBG:" + str(port.name.get()) + " - " + port.mode.get())
def _addport(self,frame):
tmp_port = Port("name", "Two", "Input")
self.ports.append(tmp_port)
self.frame_addport = tk.Frame(frame)
self.frame_addport.pack(side=tk.TOP)
if (len(self.ports) == 1):
self.button_portname = tk.Button(self.frame_addport, text = "[+] Port Name:", width=12, command=lambda:self._addport(frame))
self.button_portname.pack(side=tk.LEFT)
else:
self.label_portname = tk.Label(self.frame_addport, text = " Port Name:", width=14)
self.label_portname.pack(side=tk.LEFT, padx=4)
self.e = tk.Entry(self.frame_addport, textvariable=self.ports[-1].name)
self.e.pack(side=tk.LEFT)
for text in ["One", "Two", "Three", "Four"]:
self.b = tk.Radiobutton(self.frame_addport, text=text,
variable=self.ports[-1].mode, value=text)
self.b.pack(side=tk.LEFT)
root=tk.Tk()
MAIN_interface_pkg_window = tk.Tk()
MAIN_interface_pkg = MAIN_INTERFACE_PKG(MAIN_interface_pkg_window)
MAIN_interface_pkg_window.withdraw()
MAIN_gui= MAIN_GUI(root)
root.mainloop()
You are calling Tk() twice in your code. This results in two entirely separate Tk instances running, each with its own set of variables. I'm not sure of the exact rules here, but evidently your StringVar()s are being created in a different instance than they are being used.
To create more than one window in a Tkinter application, you have to use Toplevel() for all but one of them.

Creating new entry boxes with button Tkinter

How do i make the button to add two box (side by side) below when it is being clicked as the user decided to put more input?
def addBox():
labelframe = Tkinter.Frame()
labelframe.bind("<Add Input>", callback)
labelframe.pack()
labelframe = Tkinter.Frame()
labelFrom = Tkinter.Label(labelframe, text= "from")
labelFrom.grid(column=1, row=0)
e = Tkinter.Entry(labelframe)
e.grid(column=1, row=1)
labelTo = Tkinter.Label(labelframe, text= "to")
labelTo.grid(column=2, row=0)
e2 = Tkinter.Entry(labelframe)
e2.grid(column=2, row=1)
labelframe.pack()
addboxButton = Button( root,text='<Add Time Input>', fg="Red",command="addBox")
addboxButton.pack(side=Tkinter.TOP)
This is example how to add Entry.
Probably you get problem because you use quotation marks in command=addBox
Because you will have to get values from entries you have to remeber them on list.
I add button which print text from entries.
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
ent = Entry(root)
ent.pack()
all_entries.append( ent )
#------------------------------------
def showEntries():
for number, ent in enumerate(all_entries):
print number, ent.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
addboxButton = Button(root, text='<Add Time Input>', fg="Red", command=addBox)
addboxButton.pack()
root.mainloop()
#------------------------------------
EDIT:
Example with boxes side by side.
I use new frame to keep entries side by side using grid().
This way I don't mix grid() with pack() in main window/frame.
I use len(all_entries) to get number of next free column.
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
# I use len(all_entries) to get nuber of next free column
next_column = len(all_entries)
# add label in first row
lab = Label(frame_for_boxes, text=str(next_column+1))
lab.grid(row=0, column=next_column)
# add entry in second row
ent = Entry(frame_for_boxes)
ent.grid(row=1, column=next_column)
all_entries.append( ent )
#------------------------------------
def showEntries():
for number, ent in enumerate(all_entries):
print number, ent.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
addboxButton = Button(root, text='<Add Time Input>', fg="Red", command=addBox)
addboxButton.pack()
frame_for_boxes = Frame(root)
frame_for_boxes.pack()
root.mainloop()
#------------------------------------
EDIT:
Another example:
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
frame = Frame(root)
frame.pack()
Label(frame, text='From').grid(row=0, column=0)
ent1 = Entry(frame)
ent1.grid(row=1, column=0)
Label(frame, text='To').grid(row=0, column=1)
ent2 = Entry(frame)
ent2.grid(row=1, column=1)
all_entries.append( (ent1, ent2) )
#------------------------------------
def showEntries():
for number, (ent1, ent2) in enumerate(all_entries):
print number, ent1.get(), ent2.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
addboxButton = Button(root, text='<Add Time Input>', fg="Red", command=addBox)
addboxButton.pack()
root.mainloop()
#------------------------------------
First of all, the indentation is a whole mess, so I don't know where does the addBox function end ..
Second, I don't think you need a button, I suppose a checkbutton will do the same thing and it's also more common and familiar to users, I once had this problem and I simply created an entry box and put above it a label indicating that it's optional, and as for code, I simply ignored it if it was empty and verified the input if I found any input ..Howerver, that was for only one entry box, and you probably will need something more complex ..
See this ..
class OptionsView(Frame):
"""Frame for options in main window"""
def __init__(self, x, y, parent):
Frame.__init__(self, parent)
self.x = x
self.y = y
self.placed = False
self.hidden = False
self.btn = Button(self, text = 'Button attached to the frame ..', command = lambda: print('Button in frame clicked ..')).pack()
def pack(self):
self.place(x = self.x, y = self.y)
self.placed = True
def toggle_view(self):
if self.hidden:
self.pack()
self.hidden = False
else:
self.place_forget()
self.hidden = True
if __name__ == '__main__':
def m_frame():
if val.get() and not options_frame.placed:
print('Showing Frame ..')
options_frame.pack()
else:
print('Toggling Frame ..')
options_frame.toggle_view()
root = Tk()
root.geometry('300x400+500+600')
root.title('Testing Hiding Frames ..')
options_frame = OptionsView(200, 300, root)
val = BooleanVar(value = False)
Checkbutton(text = 'View more Options ..', var = val, command = m_frame).place(x=root.winfo_height()/2, y=root.winfo_width()/2)
try: root.mainloop()
except e: showerror('Error!', 'It seems there\'s a problem ..', str(e))
Ofcourse you can also modify the length and the x axis of the main window if you want to be more realistic ..

Creating elements by loop Tkinter

I'm looking for a way to create elements dynamically in Tkinter. For example, say the user enters 5, I'd like a loop to create 5 radio buttons and entries next to them.
Here's a simple example to get you started:
import Tkinter as tk
class ButtonBlock(object):
def __init__(self, master):
self.master = master
self.button = []
self.button_val = tk.IntVar()
entry = tk.Entry()
entry.grid(row=0, column=0)
entry.bind('<Return>', self.onEnter)
def onEnter(self, event):
entry = event.widget
num = int(entry.get())
for button in self.button:
button.destroy()
for i in range(1, num+1):
self.button.append(tk.Radiobutton(
self.master, text=str(i), variable=self.button_val, value=i,
command=self.onSelect))
self.button[-1].grid(sticky='WENS', row=i, column=0, padx=1, pady=1)
def onSelect(self):
print(self.button_val.get())
if __name__ == '__main__':
root = tk.Tk()
ButtonBlock(root)
root.mainloop()
There's nothing special about widgets. You create them in a loop the same way you would create any other object:
for i in range(5):
r = tk.Radiobutton(...)
r.pack(...) # or .grid(...)
# if you need to reference these buttons later,
# save them in a list
self.buttons.append(r)

tkinter reading checkbutton values added through a for loop

I am making a menu test for the employees at my restaurant. The plan is for menu items to loop through "Loop items here" at which time they select the correct checkbuttons (ingredients) and then click the "submit and continue button". When they click the submit button I first need to read the on and off values of the checkbuttons to determine which items they have selected, then compare those to the correct answers that I defined in a dictionary of lists, then clear all checkbuttons and whether the answer is wrong or right the program will continue on and I will eventually have a results screen but right now I am stuck on how to read the checkbutton on and off values. I am simply trying to print the selected veggies right now and cant figure it out.
I think it has to do with the fact they are in different methods and also the fact that they were added in a loop? I am not sure exactly but I know my code is trying to read the wrong thing and any help would be greeeeatly appreciated!
Sorry for the lengthy question I just thought it would be beneficial to give you as much info as possible to understand what I am trying to do..
from tkinter import *
class GUI(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.grid()
self.parent.title("Wahoos Menu Test")
self.create_buttons()
global count
count = -1
def create_buttons(self):
for r in range(20):
for c in range(14):
Label(self, text='',
borderwidth=0).grid(row=r,column=c)
B = Button(self, text ="Begin Exam", relief=RIDGE, fg="black", command= self.on_button_press).grid(row=19, column=7)
L = Label(self, text="What comes in the following", fg="blue").grid(row=6, column=0)
self.veg = ['Lettuce', 'Cabbage', 'Cheese', 'Ahee Rice', 'Brown Rice', 'Banzai Veg', 'Red Cabbage', 'Black Beans', 'Cajun White Beans']
self.vegboxes = []
self.opt = []
c = 1
for ve in self.veg:
c +=1
self.v = IntVar()
self.vegboxes.append(self.v)
vo = Checkbutton(self, text=ve, variable=self.v, onvalue=1, offvalue=0).grid(row=c, column=11, sticky=W)
def on_button_press(self):
global count
count = count + 1
menuItems = {'nft': ['cabbage', 'cheese', 'corn', 'nf', 'salsa'],
'nckt': ['lettuce', 'cheese', 'corn', 'nck', 'salsa']}
menu = ['blackened fish taco', 'wahoos chicken salad']
if count == len(menu):
C = Button(self, text =" Your Done! ", relief=RIDGE, fg="black").grid(row=19, column=7)
else:
m = Label(self, text=menu[count], fg="black").grid(row=7, column=0)
C = Button(self, text ="Submit and Continue", relief=RIDGE, fg="black", command= self.read_checks).grid(row=19, column=7)
def read_checks(self):
for v in self.veg:
if self.v == 1:
print(self.veg[v])
def main():
root = Tk()
app = GUI(root)
root.mainloop()
if __name__ == '__main__':
main()
You could create a dictionary and have each key be the Checkbutton's label,
and have the value be the state "Control Variable".
Then you would check the state with the Control Variable's get() method as shown in the example below.
import tkinter as tk
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.buttonDic = {
'Brown Rice':0,
'Banzai Veg':0,
'Red Cabbage':0,
'Black Beans':0
}
for key in self.buttonDic:
self.buttonDic[key] = tk.IntVar()
aCheckButton = tk.Checkbutton(self, text=key,
variable=self.buttonDic[key])
aCheckButton.grid(sticky='w')
submitButton = tk.Button(self, text="Submit",
command=self.query_checkbuttons)
submitButton.grid()
def query_checkbuttons(self):
for key, value in self.buttonDic.items():
state = value.get()
if state != 0:
print(key)
self.buttonDic[key].set(0)
gui = GUI()
gui.mainloop()
This approach allows you to create and analyze the Checkbuttons with one dictionary.
Note the use of items() in for key, value in self.buttonDic.items():
which is needed to prevent:
ValueError: too many values to unpack
More information on the Checkbutton widget and it's variable can be found: here
I'm going to include my first attempt which was based on
the Checkbutton widget's onvalue and offvalue,
in case it helps someone understand Control Variables a bit more.
import tkinter as tk
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.bRiceV = tk.StringVar()
bRice = tk.Checkbutton(self, text="Brown Rice",variable=self.bRiceV,
onvalue="Brown Rice", offvalue="Off")
bRice.pack()
self.bVegV = tk.StringVar()
bVeg = tk.Checkbutton(self, text="Banzai Veg",variable=self.bVegV,
onvalue="Banzai Veg", offvalue="Off")
bVeg.pack()
self.varList = [self.bRiceV, self.bVegV]
submitButton = tk.Button(self, text="Submit",
command=self.query_checkbuttons)
submitButton.pack()
def query_checkbuttons(self):
for var in self.varList:
value = var.get()
if value != 'Off':
print(value)
var.set('Off')
gui = GUI()
gui.mainloop()

Categories

Resources