How to get the text of Checkbuttons? - python

Checkbuttons gets generated dynamically and they are getting text from a python list.
I need a logic for capturing selected checkbuttons text .
As per my research everywhere they are returning the state of checkbox instead of text.
Please help.
cb_list =['pencil','pen','book','bag','watch','glasses','passport','clothes','shoes','cap']
try:
r = 0
cl = 1
for op in cb_list:
cb = Checkbutton(checkbutton_frame, text=op, relief=RIDGE)
cb.grid(row=r, column=cl, sticky="W")
r = r + 1
except Exception as e:
logging.basicConfig(filename=LOG_FILENAME, level=logging.ERROR)
logging.error(e)
# print (e)
selected_item = Text(self, width=30, height=20, wrap=WORD)
selected_item.grid(row=1, column=6, padx=20, pady=20, columnspan=2, sticky=E)
display_button = Button(self, text='DISPLAY', command=display()
convert_button.grid(row=1, column=8, padx=20, pady=20)

The idea is to associate one BooleanVar to each checkbutton and store them in a list cb_var. Then, to display the selected items, we just have to clear the display box (I have used a Listbox) and then loop simultaneously through cb_list and cb_var to determine which items are selected:
import tkinter as tk
root = tk.Tk()
checkbutton_frame = tk.Frame(root)
checkbutton_frame.grid(row=1, column=0)
def display():
# clear listbox
selected_item.delete(0, 'end')
# add selected items in listbox
for text, var in zip(cb_list, cb_var):
if var.get():
# the checkbutton is selected
selected_item.insert('end', text)
cb_list = ['pencil','pen','book','bag','watch','glasses','passport','clothes','shoes','cap']
cb_var = [] # to store the variables associated to the checkbuttons
cl = 1
for r, op in enumerate(cb_list):
var = tk.BooleanVar(root, False)
cb = tk.Checkbutton(checkbutton_frame, variable=var, text=op, relief='ridge')
cb.grid(row=r, column=cl, sticky="w")
cb_var.append(var)
selected_item = tk.Listbox(root, width=30, height=20)
selected_item.grid(row=1, column=6, padx=20, pady=20, columnspan=2, sticky='e')
display_button = tk.Button(root, text='DISPLAY', command=display)
display_button.grid(row=1, column=8, padx=20, pady=20)
root.mainloop()
EDIT: If you want to be able to change the list of items easily, you can use a function init_checkbuttons to create the checkbuttons from your list
of items. This function does the following things:
Destroy all previous checkbuttons
Clear the listbox
Create the new checkbuttons
Change the command of the display button
You can notice that the display function now takes cb_list and cb_var in argument, so that you can change them.
import tkinter as tk
root = tk.Tk()
checkbutton_frame = tk.Frame(root)
checkbutton_frame.grid(row=1, column=0)
def display(cb_list, cb_var):
# clear listbox
selected_item.delete(0, 'end')
# add selected items in listbox
for text, var in zip(cb_list, cb_var):
if var.get():
# the checkbutton is selected
selected_item.insert('end', text)
def init_checkbuttons(cb_list, cl=1):
# destroy previous checkbuttons (assuming that checkbutton_frame only contains the checkbuttons)
cbs = list(checkbutton_frame.children.values())
for cb in cbs:
cb.destroy()
# clear listbox
selected_item.delete(0, 'end')
# create new checkbuttons
cb_var = [] # to store the variables associated to the checkbuttons
for r, op in enumerate(cb_list):
var = tk.BooleanVar(root, False)
cb = tk.Checkbutton(checkbutton_frame, variable=var, text=op, relief='ridge')
cb.grid(row=r, column=cl, sticky="w")
cb_var.append(var)
# change display command
display_button.configure(command=lambda: display(cb_list, cb_var))
cb_list = ['pencil', 'pen', 'book', 'bag', 'watch', 'glasses', 'passport', 'clothes', 'shoes', 'cap']
cb_list2 = ['ball', 'table', 'bat']
selected_item = tk.Listbox(root, width=30, height=20)
selected_item.grid(row=1, column=6, padx=20, pady=20, columnspan=2, sticky='e')
display_button = tk.Button(root, text='DISPLAY')
display_button.grid(row=1, column=8, padx=20, pady=20)
tk.Button(root, text='Change list', command=lambda: init_checkbuttons(cb_list2)).grid(row=2, column=8)
init_checkbuttons(cb_list)
root.mainloop()

Instead of overwriting the same variable, cb, try using an iterable type such as dictionary. You should also need to be attaching the value of Checkbutton to a tkinter variable class, such as BooleanVar, in order to easily track its status & value.
The code below produces a GUI that re-writes Text each time a Checkbutton is selected. It first populates a dictionary, cbs, with items from a list, cb_list, as keys and tk.Checkbutton objects as the values.
Checkbutton objects are so that each is attached to a special object, Tkinter Variable class, BooleanVar, which has a get method that returns the Checkbutton it is attached to's current value when called. In this case, each Checkbutton holds True if checked, and False if unchecked as its value.
Each Checkbutton is also attached to a method, update_text, which is called when any of the Checkbutton is pressed. In that method for every Checkbutton in cbs, it first checks if the Checkbutton has True value, if so it appends its text to a _string. After this has been done for all Checkbuttons, the method then proceeds as first deleteing the entire text in the Text widget, then it puts _string to the Text.
The code:
import tkinter as tk
def update_text():
global cbs
_string = ''
for name, checkbutton in cbs.items():
if checkbutton.var.get():
_string += checkbutton['text'] + '\n'
text.delete('1.0', 'end')
text.insert('1.0', _string)
if __name__ == '__main__':
root = tk.Tk()
text = tk.Text(root)
cb_list =['pencil','pen','book','bag','watch','glasses','passport',
'clothes','shoes','cap']
cbs = dict()
for i, value in enumerate(cb_list):
cbs[value] = tk.Checkbutton(root, text=value, onvalue=True,
offvalue=False, command=update_text)
cbs[value].var = tk.BooleanVar(root, value=False)
cbs[value]['variable'] = cbs[value].var
cbs[value].grid(row=i, column=0)
text.grid()
root.mainloop()
text is an option to Checkbutton widget, which means you can get its value using cget(widget.cget('option')) or simply widget['option'].

Related

return values to a list from a listbox or a button using tkinter python

i'm trying to get the selected values from a list box.
the button that i've created only select and print those items,
but what i really want to do is to return those item into a list and used them in my code
for other purpose.
is there anyway to return a list from a listbox using a buttom
or any other way which i can get the values from the listbox?
from tkinter import *
root = Tk()
root.title("blabla")
root.geometry("600x650")
Label(text="", width=15).grid(row=0, column=0)
Label(text="Choose ingredients:", width=15).grid(row=1, column=0)
ingredients_listbox =Listbox(root, width=20, height=10)
ingredients_listbox.grid(row=2, column=0)
# create a vertical scrollbar to the right of the listbox
ingredients_scroll =Scrollbar(command=ingredients_listbox.yview, orient=VERTICAL)
ingredients_scroll.grid(row=2, column=1, sticky='ns')
ingredients_listbox.configure(yscrollcommand=ingredients_scroll.set, selectmode = MULTIPLE)
ingredients_list = ["None","eggplant","red_bell_pepper","tomato","onion","garlic","coriander",
"zucchini","artichoke","mushrooms","olives","parsley","cauliflower"]
for item in ingredients_list:
ingredients_listbox.insert(END,item)
def select_ingredients():
#print(ingredients_listbox.curselection())
ingredients_result = []
for item in ingredients_listbox.curselection():
ingredients_result.append(str(ingredients_listbox.get(item)))
print(ingredients_result)
return ingredients_result
ingredients_button = Button(root, text = "Add ingredients", command = select_ingredients).grid(row=3, column=0)

Focus Events (or lack thereof)

I am having a hard time understanding the focus events for Entry and Textbox fields in Python version 3 using Tk. I eventually need to validate an Entry box on lost focus if I click a radio option or a button.
If you run the code below then (which serves only to demonstrate Focus issues not the validation i require elsewhere), place the cursor in either of the top row Entry boxes and click between the other widgets, the only time FocusIn and Focus out events occur are on the widgets that accept input ie Text/Entry boxes.
Clicking the button or the radio options, the cursor remains in the Entry or Textbox widgets. Why when i have clearly focused on a radio option or the button.
I have tried .bind FocusIn/Out events and still no joy. if anyone has an explanation I would be intrigued to know why and possibly how i can overcome it.
from tkinter import *
root = Tk()
root.title("My Widgets")
root.update_idletasks()
root.geometry("350x200+10+300")
root.attributes("-toolwindow",1)
root.resizable(width=FALSE, height=FALSE)
root.config(bg="blue")
# function below output to the console and label the focus results
def Validate(a,b,c,d,e,f,g,h):
text = g + ' on ' + h
lblOutputVar.set(text)
print(f,g,h)
return True
var = IntVar()
lblOutputVar = StringVar()
vcmd=(root.register(Validate),'%d','%i','%P','%s','%S','%v','%V','%W')
entryOne = Entry(root, name = 'entryBoxOne')
entryOne.config(validate = 'all',vcmd=vcmd)
entryOne.grid(row=1, column=1,padx=(0,0),pady=(10,10),ipady=(1), sticky=E+W)
entryTwo = Entry(root, name = 'entryBoxTwo')
entryTwo.config(validate = 'all',vcmd=vcmd)
entryTwo.grid(row=1, column=2,padx=(10,0),pady=(10,10),ipady=(1), sticky=E+W)
txtBox = Text(root, name = 'textBox', width=10, height=1, takefocus = 0)
txtBox.grid(row=5, column=1, sticky=E+W)
aButton = Button(root, text = 'Click Me!', takefocus=1)
aButton.grid(row=5, column=2)
lblOutput = Label(root, name = 'labelOutput', width=20, height=2, textvariable=lblOutputVar)
lblOutput.grid(row=10, column=1, columnspan =2, pady=(5,0), sticky=E+W)
radioOne = Radiobutton(root, anchor = 'w', text = 'One', variable = var, value = 1, takefocus = 1)
radioOne.grid(row=2, column=1, sticky=E+W)
radioTwo = Radiobutton(root, anchor = 'w', text = 'Two', variable = var, value = 2, takefocus = 1)``
radioTwo.grid(row=3, column=1, sticky=E+W)
root.mainloop()
The explanation is simply that tkinter buttons and radiobuttons aren't given focus when you click on them. If you want that to happen, you need to set up a binding to explicitly give them the focus.
Your other option is to use a ttk radiobutton which does get focus. It's unfortunate that the two different radiobuttons have different behavior.

Set Entry widget values dynamically in Tkinter

I have a window to browse a folder containing necessary files. I am using tkFileDialog for the same. I want to set the value of Entry widget equal to this selected folder. Initially when no folder is selected it will be null. As soon as I select the folder, the path of the selected folder should appear in the Entry widget. The user should be able to modify.Below mentioned is the code for the same.
from Tkinter import *
from tkFileDialog import *
class Checkit:
root = Tk()
#default string to be displayed in the entry of path
path_to_file = StringVar(root, value="abc")
def __init__(self):
self.inputDetail()
def inputDetail(self):
#copy the root window
master = self.root
#create frame for details in the root window
details_frame = Frame(master)
details_frame.grid(row=0, column=0)
#Create the Labels
papercode_label = Label(details_frame, text="Paper code:")
subject_label = Label(details_frame, text="Subject:")
chapter_label = Label(details_frame, text="Chapter:")
batch_label = Label(details_frame, text="Batch:")
ansFolder_label = Label(details_frame, text="Folder containing answer-keys:")
#create entry for the labels
papercode_entry = Entry(details_frame)
subject_entry = Entry(details_frame)
chapter_entry = Entry(details_frame)
batch_entry = Entry(details_frame)
ansFolder_entry = Entry(details_frame)
#create button to add path
path = Button(details_frame, text="Browse", command= lambda: self.addpath(details_frame))
#button to enter the next window
next = Button(details_frame, text="Next", command= lambda: self.checkOmr(details_frame, master))
#Use grid layout to place labels and entry
papercode_label.grid(row=0, sticky=W)
papercode_entry.grid(row=1, sticky=W)
subject_label.grid(row=2, sticky=W)
subject_entry.grid(row=3, column=0, sticky=W)
chapter_label.grid(row=4, sticky=W)
chapter_entry.grid(row=5, column=0, sticky=W)
batch_label.grid(row=6, sticky=W)
batch_entry.grid(row=7, column=0, sticky=W)
ansFolder_label.grid(row=8, sticky=W)
path.grid(row=9, sticky=W, columnspan=2)
next.grid(row=10, sticky=E, columnspan=2)
master.mainloop()
def checkOmr(self, old_frame, master):
#destoy the old frame
old_frame.destroy()
#create frame for details in the root window
inputPath_frame = Frame(master)
inputPath_frame.grid(row=0, column=0)
#create label to input folder containing
omrFolder_label = Label(inputPath_frame, text="Folder containing OMR sheet to be checked:")
#create button to add path
path = Button(inputPath_frame, text="Browse", command= lambda: self.addpath(inputPath_frame))
selected_path = Entry(inputPath_frame, textvariable=self.path_to_file)
#place the label and button on the grid
omrFolder_label.grid(row=0, sticky=W)
path.grid(row=1, column=0, sticky=W)
selected_path.grid(row=1, column=1, sticky=W)
#master.mainloop()
def addpath(self, details_frame):
self.path_to_file = askdirectory(parent=details_frame,initialdir="/",title='Please select a directory')
if __name__=='__main__':
handle = Checkit()
Here I am trying to change the modifying the self. path_to_file value on the click of the button. I tried to print the value of self.path_to_file value in addpath(). It gives correct result there but the value in the Entry selected_path in checkOMR() does not modify.
Can somebody suggest what changes should I make to make that thing possible.
Look at this line:
self.path_to_file = askdirectory(...)
Before this line of code runs, self.path_to_file is an instance of a StringVar. After this line of code has run, self.path_to_file is reset to be just a string.
Assuming you want self.path_to_file to remain an instance of StringVar, you need to change that line to this:
path = askdirectory(...)
self.path_to_file.set(path)

tkinter dynamic OptionMenu command not working

I'm using python 2.7.9 and my current issue is that for some reason, my OptionMenu's command isn't working. Below is sample code of what I mean.
from Tkinter import *
root = Tk()
var = StringVar()
var.set("Choose a name...")
names = []
# Appends names to names list and updates OptionMenu
def createName(n):
names.append(n)
personName.delete(0, "end")
menu = nameMenu['menu']
menu.delete(0, "end")
for name in names:
menu.add_command(label=name, command=lambda name=name: var.set(name))
# what to run when a name is selected
def selection():
print "Running" # For testing purposes to see when/if selection runs
print var.get()
# Option Menu for names
nameMenu = OptionMenu(root, var, (), command=lambda: selection())
nameMenu.grid(row=0, column=0, columnspan=2)
nameMenu.config(width=20)
# Entry for user to submit name
Label(root, text="Name").grid(row=1, column=0)
personName = Entry(root, width=17)
personName.grid(row=1, column=1)
# Add person Button
Button(root, text="Add Person", width=20, command=
lambda: createName(personName.get())).grid(row=5, column=0, columnspan=2)
mainloop()
The purpose of this theoretical program is just to add a name to the OptionMenu, and then when you select the name, it will print it. I can add names to the OptionMenu just fine, but when it comes time for the OptionMenu to run the selection() function, it won't.
Now my best guess as to what's wrong is simply that the createName() function that the button is calling is also using the OptionMenu's command up due to the line
menu.add_command(label=name, command=lambda name=name: var.set(name))
Is there anyway around this? Is it possible for an OptionMenu to have multiple commands?
You're on the right track... But instead of changing the StringVar you can pass the name into your selection() function like this:
from Tkinter import *
root = Tk()
var = StringVar()
var.set("Choose a name...")
names = []
# Appends names to names list and updates OptionMenu
def createName(n):
names.append(n)
personName.delete(0, "end")
menu = nameMenu['menu']
menu.delete(0, "end")
for name in names:
menu.add_command(label=name, command=lambda name=name: selection(name))
# what to run when a name is selected
def selection(name):
var.set(name)
print "Running" # For testing purposes to see when/if selection runs
print name
# Option Menu for names
nameMenu = OptionMenu(root, var, ())
nameMenu.grid(row=0, column=0, columnspan=2)
nameMenu.config(width=20)
# Entry for user to submit name
Label(root, text="Name").grid(row=1, column=0)
personName = Entry(root, width=17)
personName.grid(row=1, column=1)
# Add person Button
Button(root, text="Add Person", width= 20, command=lambda: createName(personName.get())).grid(row=5, column=0, columnspan=2)
mainloop()

Tkinter. Press Enter in Entry box. Append to Text box. How?

I am making a chat program and decided to use Tkinter for the interface.
What I wanna do is a breeze in C# but Tkinter is new to me.
Basically I have a form with a Entry control and a Text control.
I want to know how to append text from the Entry control to the Text control after the user presses Enter.
Here's my code so far:
from tkinter import *
class Application:
def hello(self):
msg = tkinter.messagebox.askquestion('title','question')
def __init__(self, form):
form.resizable(0,0)
form.minsize(200, 200)
form.title('Top Level')
# Global Padding pady and padx
pad_x = 5
pad_y = 5
# create a toplevel menu
menubar = Menu(form)
#command= parameter missing.
menubar.add_command(label="Menu1")
#command= parameter missing.
menubar.add_command(label="Menu2")
#command= parameter missing.
menubar.add_command(label="Menu3")
# display the menu
form.config(menu=menubar)
# Create controls
label1 = Label(form, text="Label1")
textbox1 = Entry(form)
#command= parameter missing.
button1 = Button(form, text='Button1')
scrollbar1 = Scrollbar(form)
textarea1 = Text(form, width=20, height=10)
textarea1.config(yscrollcommand=scrollbar1.set)
scrollbar1.config(command=textarea1.yview)
textarea1.grid(row=0, column=1, padx=pad_x, pady=pad_y, sticky=W)
scrollbar1.grid(row=0, column=2, padx=pad_x, pady=pad_y, sticky=W)
textbox1.grid(row=1, column=1, padx=pad_x, pady=pad_y, sticky=W)
button1.grid(row=1, column=2, padx=pad_x, pady=pad_y, sticky=W)
form.mainloop()
root = Tk()
Application(root)
So you're using a tkinter.Text box, which supports the .insert method. Let's use it!
def __init__(self,form):
# Lots of your code is duplicated here, so I'm just highlighting the main parts
button1 = Button(form, text='Button1', command = self.addchat)
self.textbox = textbox1 # to make it accessible outside your __init__
self.textarea = textarea1 # see above
form.bind("<Return>", lambda x: self.addchat())
# this is the magic that makes your enter key do something
def addchat(self):
txt = self.textbox.get()
# gets everything in your textbox
self.textarea.insert(END,"\n"+txt)
# tosses txt into textarea on a new line after the end
self.textbox.delete(0,END) # deletes your textbox text

Categories