Set Entry widget values dynamically in Tkinter - python

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)

Related

python 3 Tkinter ComboBox don't get value

I am trying to get the value of from a combobox in tkinter using python 3.6, i been looking to many tutorials but i don't see the problem yet.
every time i press the button don't show anything.
but also there is not errors.
so to clarify ... I am trying to get the value of the tk.combobox when i press ttk.Button.
thank you in advance for any ideas or comments.
this is what i have so far.
import tkinter as tk
from tkinter import ttk
def combo_box_updater():
total_location = ['linden', 'mineola', 'brooklyn']
return total_location
def start_analisys(event=None):
site = jobsite_name.get()
print(site)
# this is part of a definition that automatically will update the names in later versions
job_site = combo_box_updater()
# basic gui setup
unified = tk.Toplevel()
unified.title('Unified 1 Week Timesheet')
unified.configure(background="#00012f")
unified.geometry("650x200")
unified.resizable(width=False, height=False)
entry_width = 30
# basic frame
frame1 = tk.Frame(unified)
frame1.grid(row=0, column=0, sticky='w')
# combo box in the fourth row
jobsite_name = tk.StringVar()
combo_box = ttk.Combobox(frame1, font="none 12 bold", width=20, textvariable=jobsite_name, text="choose location")
combo_box.grid(row=0, column=1, sticky="wesn")
combo_box['values'] = [x for x in job_site]
# Left button side
ttk.Button(frame1, text='Run', command=start_analisys, ).grid(row=0, column=2, sticky='nsew', rowspan=3)
unified.mainloop()
Made three minor edits to your code: added a label to display the result, added a line to combo box setup, and changed the creation of the main window.
import tkinter as tk
from tkinter import ttk
def combo_box_updater():
total_location = ['linden', 'mineola', 'brooklyn']
return total_location
def start_analisys(event=None):
site = jobsite_name.get()
aLabel["text"] = site
print(site)
# this is part of a definition that automatically will update the names in later versions
job_site = combo_box_updater()
# basic gui setup
unified = tk.Tk()
unified.title('Unified 1 Week Timesheet')
unified.configure(background="#00012f")
unified.geometry("650x200")
unified.resizable(width=False, height=False)
entry_width = 30
# basic frame
frame1 = tk.Frame(unified)
frame1.grid(row=0, column=0, sticky='w')
# combo box in the fourth row
jobsite_name = tk.StringVar()
combo_box = ttk.Combobox(frame1, font="none 12 bold", width=20, textvariable=jobsite_name)
combo_box.grid(row=0, column=1, sticky="wesn")
combo_box['values'] = [x for x in job_site]
combo_box.current(0)
# Left button side
ttk.Button(frame1, text='Run', command=start_analisys, ).grid(row=0, column=2, sticky='nsew', rowspan=3)
# add a label
aLabel = ttk.Label(frame1, text='My Label')
# place the label
aLabel.grid(column=3, row=0)
unified.mainloop()
if __name__ == '__main__':
pass
When you add the values as an afterthought like that you need to add the corresponding commands as well. It's much better to add the values through the init method so the commands are automatically added:
jobsite_name = tk.StringVar(value="choose location")
combo_box = ttk.Combobox(frame1, textvariable=jobsite_name, values=job_site, font="none 12 bold", width=20)

How to get the text of Checkbuttons?

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'].

Returning variables from Tkinter GUI

I'm looking at using a simple, currently ugly, GUI built with Tkinter to attain two variables from the user. Namely a file path and a choice from a dropdown (OptionMenu).
The variables selected will be used later in the Python script, which is where I'm running into difficulty. Put simply, how to asign the users choices to the variables: Carrier, Path.
Please see below for sample code:
from Tkinter import *
from tkFileDialog import askopenfilename
def Choose_Path():
Tk().withdraw()
return askopenfilename()
root = Tk()
root.geometry('400x400')
root.configure(background='#A2B5CD')
C_Label = Label(root, text='Carrier Choice:', bg='#A2B5CD', fg='black',font=('Calibri', 12))
C_Label.grid(row=0,sticky=W, padx =10)
I_Label = Label(root, text='Invoice Path:', bg='#A2B5CD', fg='black',font=('Calibri', 12))
I_Label.grid(row=1, sticky=W, padx =10)
var = StringVar(root)
var.set('Choose Carrier...')
option = OptionMenu(root, var, 'DHL','DPD','DX','Fedex','Geodis','Hermes','WN Direct')
option.config(relief=RAISED, highlightbackground='#A2B5CD')
option.grid(row=0,column=1, sticky=W, pady = 10)
browser = Button(root, text = 'Browse Invoice...', command=Choose_Path)
browser.grid(row=1, column=1, sticky=W, pady=10)
Button(root, text='Accept and Close').grid(column=1, sticky=S)
root.mainloop()
Any feedback would be appreciated. Thanks in advance.
Through a combination of your feedback and a little more playing around with an extra function, I now seem to be getting the results that I need. See below for what it looks like now.
from Tkinter import *
from tkFileDialog import askopenfilename
path = []
def Choose_Path():
Tk().withdraw()
path.append(askopenfilename())
def CloseGUI():
root.quit()
root.destroy()
root = Tk()
root.geometry('400x400')
root.configure(background='#A2B5CD')
C_Label = Label(root, text='Carrier Choice:', bg='#A2B5CD', fg='black',font=('Calibri', 12))
C_Label.grid(row=0,sticky=W, padx =10)
I_Label = Label(root, text='Invoice Path:', bg='#A2B5CD', fg='black',font=('Calibri', 12))
I_Label.grid(row=1, sticky=W, padx =10)
var = StringVar(root)
var.set('Choose Carrier...')
option = OptionMenu(root, var, 'DHL','DPD','DX','Fedex','Geodis','Hermes','WN Direct')
option.config(relief=RAISED, highlightbackground='#A2B5CD')
option.grid(row=0,column=1, sticky=W, pady = 10)
browser = Button(root, text = 'Browse Invoice...', command=Choose_Path)
browser.grid(row=1, column=1, sticky=W, pady=10)
b1 = Button(root, text='Accept and Close', command = CloseGUI).grid(column=1, sticky=S)
mainloop()
print var.get()
print path
Thanks for your help! +1
Two issues:
-You're going to have to figure out when to end your root's mainloop. From the moment you call root.mainloop(), currently the program will not advcance to the next line (which you don't have, but I assume you will in your final program) until you close the Tk window.
-After the mainloop has ended, you need to have your variable values somewhere. Currently, the option object (which is an OptionMenu instance) will contain the value if your carrier, so you can just do something like option.get().
The filename is slightly more complicated, because you don't store that somewhere: you return it from Choose_Path() but the return value isn't stored anywhere. Probably you're going to have to store this value in a global. (This storing has to happen within Choose_Path, e.g. FileName = askopenfilename() instead of return askopenfilename()).

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