How to create entry inputs in a toplevel window - python

i have a problem and can't get my head around it. How to create a child window on pressing a button using tkinter in python were I can entry values like for example:
import tkinter
root = Tk()
Button(root, text='Bring up Message', command=Window).pack()
root.mainloop()
def messageWindow():
win = Toplevel()
-------->calculate------
Label(win, text=message).pack()
Button(win, text='OK', command=win.destroy).pack()
and on the message window i would like to have two entry fields were I can enter a and b and afterwards it should calc a+b and give me the result.
Thank you.

First, you should use from tkinter import * since there isn't a tkinter. preceding the module's classes used in your script.
Also, is your "Bring up Message" button supposed to call the messageWindow() function? Right now it's calling an undefined function Window. If so, you should change the Button's command and move your messageWindow() function above the line where you created the button or else it will call the function before it is defined and generate an error.
The syntax of an Entry widget in Tkinter goes as follows:
entry = Entry(root, *options)
entry.pack()
You need to pack() the entry widget after you define it. You won't be able to retrieve the input inside it if you pack() it on the same line as you define it as it will become a NoneType object.
You will need at least two Entry widgets, one to enter input a and one to enter input b.
You can also add a third Entry to print the result of the sum of a and b to, though you can use a label or just print it to the console.
entry_a = Entry(win)
entry_a.pack()
entry_b = Entry(win)
entry_b.pack()
# Optional answer entry
entry_ans = Entry(win)
entry_ans.pack()
You should then create a function (still within the messageWindow() function) that will retrieve the input from the two entries and add them, as well as another Button to call that function. I implemented some additional error-checking in the form of a try-except for when the entries are blank or contain something other than integers:
def add():
try:
a = int(entry_a.get())
b = int(entry_b.get())
ab_sum = a + b
# Optional printing to answer entry
entry_ans.delete(0, 'end')
entry_ans.insert(0, ab_sum)
except:
pass
Button(win, text="Add", command=add).pack()

"How to create entry inputs in a toplevel window"
import tkinter as tk
...
toplevel = tk.Toplevel(...)
tk.Entry(toplevel)
"How to create a child window on pressing a button..."
import tkinter as tk
...
def create_child_window(widget):
tk.Toplevel(widget)
...
root = tk.Tk()
tk.Button(root, command=lambda w = root: create_child_window(w))

Related

python - Converting entry() values to upper case

I want to make the values I type on Entry field to be automatically converted to uppercase. I have code in here that only accepts uppercase letters to be typed in the entry using validatecommand.
from tkinter import *
root = Tk()
def text(a,b,c):
ind=int(b)
if c == '1': #insert
if not a[ind].isupper():
return False
return True
entry = Entry(root, validate="key")
entry['validatecommand'] = (entry.register(text),'%P','%i','%d')
entry.pack()
root.mainloop()
If you want to convert the entry content to uppercase instead of preventing the user to insert non uppercase letters, you can associate a StringVar to your entry and use its trace (trace_add since python 3.6) method to convert the entry content to uppercase each time the user modifies the entry.
trace takes two arguments: the mode and the callback. The mode determines when the callback is called. The modes are:
'w' ('write' for python 3.6): the callback is called when the variable is written (it's the mode I use in the code below),
'r' ('read'): the callback is called when the variable is read,
'u' ('unset'): the callback is called when the variable is deleted
For more details about the arguments of the callback, see What are the arguments to Tkinter variable trace method callbacks?
import tkinter as tk
def to_uppercase(*args):
var.set(var.get().upper())
root = tk.Tk()
var = tk.StringVar(root)
e = tk.Entry(root, textvariable=var)
e.pack()
try:
# python 3.6
var.trace_add('write', to_uppercase)
except AttributeError:
# python < 3.6
var.trace('w', to_uppercase)
root.mainloop()
You can bind to an event instead of using .trace (in python 3.x, not tested in 2.x).
The following is copied verbatum from the accepted answer (by "bevdet") to
https://bytes.com/topic/python/answers/897918-how-do-i-make-tkinter-text-entry-all-uppercase.
You can bind an event to your widget that calls a function to convert the text to upper case.
You will need to initialize a textvariable for the Entry widget. In your case, there is nothing else to take the focus, otherwise you could bind < FocusOut > to the widget. < KeyRelease > works nicely however.
from Tkinter import *
win = Tk()
def caps(event):
v.set(v.get().upper())
Label(win, text='Enter user nick:').pack(side=LEFT)
v = StringVar()
w = Entry(win, width=20, textvariable=v)
w.pack(side=LEFT)
w.bind("<KeyRelease>", caps)
mainloop()
I was able to use this method in combination with custom validation (See B. Oakley answer to
Interactively validating Entry widget content in tkinter) by placing the binding OUTSIDE the validation function, immediately after creating the Entry widget. Important: Do not put the binding inside the validation function, doing so will break the validation function (see accepted answer to Python tkInter Entry fun for explanation and a possible workaround).

Convert Tkinter textbox entry into Python Variable

(Long Question)
I'm trying to write a piece of code that will take a file path from the user using a tkinter textbox when a button is pressed. It would then convert that textbox entry to a string attached to a normal python variable so I can use that variable in a function later to use that file. The code I attached can make the label copy the text box entry, but I cannot use that variable or myvar in "normal python code". Also, in the code I tried returning myvar.get() through the function mywarWritten, but I cant set a variable equal to the mywarWritten(parameters) because that is dependent on the textbox entry that doesn't happen until the button is pressed. When the button is pressed the print function works printing the statement but it doesn't return please when the function is set equal to attempt.
(In Short)
I want to take a value, or string, from the user using a Tkinter text box, and use the entry as a normal python variable. Preferably the value in the text box would only be taken when a button is pressed.
from Tkinter import *
import Tkinter as tk
root = Tk()
root.title("MyApp")
myvar = StringVar()
def mywarWritten(*args):
print "mywarWritten",myvar.get()
please = myvar.get()
return please
#trying to make the function return the textbox entry but fails
attempt = mywarWritten()
print "plz %s" % (attempt)
#trying to just set it equal too but also fails
python_variable = myvar.get()
label = Label(root, textvariable=myvar)
label.pack()
text_entry = tk.Entry(root, textvariable=myvar)
button1 = tk.Button(root, text="Back to Home", command=lambda: mywarWritten())
button1.pack()
text_entry.pack()
#trying attempt and pythonvariable in "normal python code"
print attempt
print pythonvariable
root.mainloop()
Thanks for the help in advance.
You seem to have a few misunderstandings about scope, imports, references, and functions. myvar is already accessible, and all you have to do to access it is get() it. Don't import the same module multiple times, and try to avoid from x import *. Returning a value to a button doesn't make any sense and has no effect. Every line of code not in a function or class is executed immediately, so attempt = mywarWritten() and all of the other several times you did that outside a function will get the value of that StringVar as soon as the program runs, before there's anything in it. And lambda: func() is just func.
import Tkinter as tk
root = tk.Tk()
root.title("MyApp")
myvar = tk.StringVar()
def mywarWritten(*args):
print "mywarWritten", myvar.get()
label = tk.Label(root, textvariable=myvar)
label.pack()
text_entry = tk.Entry(root, textvariable=myvar)
button1 = tk.Button(root, text="Back to Home", command=mywarWritten)
button1.pack()
text_entry.pack()
root.mainloop()
Any time you want to access the contents of that entry widget, just do myvar.get() and there it will be.
You also have mywarWritten instead of my_var_written, with a v for var.
Overall, I very highly recommend you read the official Python tutorial (and use Python 3, because it's better than Python 2).

How to update the command of an OptionMenu

I am trying to set or update the command of an OptionMenu after its instantiation.
The widget.configure(command=foo) statement works for Button and CheckButton, but not for OptionMenu.
The following code raises this error: _tkinter.TclError: unknown option "-command"
from Tkinter import Tk, OptionMenu, StringVar
root = Tk()
var = StringVar()
def foo(val):
print val, var.get()
widget = OptionMenu(root, var, "one", 'two')
widget.configure(command=foo)
widget.pack()
root.mainloop()
Good question! Its a good thing I never had to do this in any one of my projects before because (unless someone proves me wrong here) you can't set/update the command of a OptionMenu widget once its already defined.
If Tkinter wanted you to be able to do that, it definitely would've included it to be edited by .configure()
There is a handy function called .keys() which you can call with a widget object to see all available traits that can be used with .configure().
Button example:
from tkinter import *
master = Tk()
def callback():
print ("click!")
b = Button(master, text="OK", command=callback)
print (b.keys()) #Printing .keys()
b.pack()
mainloop()
Which results in :
Notice how in this huge list of keys, 'command' is on the second line? That is because a button's command CAN be used in .configure()
OptionMenu example:
from tkinter import *
root = Tk()
var = StringVar()
def foo(val):
print ("HI")
widget = OptionMenu(root, var, "one", 'two')
print(widget.keys())
widget.pack()
root.mainloop()
Which results in:
Notice how there is no 'command' on line 2 this time. This is because you cant configure command with an OptionMenu widget.
Hopefully this problem doesn't hinder your program too much and I hope my answer helped you understand better!
I think what you're really asking is how to associate a command to an Optionmenu, rather than update a command (there is no command, so there's nothing to update).
If you want a function to be called every time a value is selected from an Optionmenu, you can add a trace on the related variable. The trace will call a function whenever that variable changes, whether through the Optionmenu or any other means.
For example:
...
var = tk.StringVar()
def foo(*args):
print "the value changed...", var.get()
var.trace("w", foo)
...
When the function is called it will pass three arguments, which you can safely ignore in this case.
For more information on variable traces see http://effbot.org/tkinterbook/variable.htm
You might also want to consider switching to the ttk combobox. It supports binding to <<ComboboxSelected>>, which is every so slightly less clunky than doing a variable trace.
It is possible to change the commands associated with OptionMenu widets if you're careful (as #Bryan Oakley commented). Below is an example of doing it.
The tricky part is you have to reconfigure all the menu items, not just one of them. This requires some extra bookkeeping (and some processing overhead, but it's unnoticeable).
Initially the menu has three items, each with a different function to be called when selected, one of which changes the menu. If the latter is selected the menu is changed to only have two menu items both of which call the same function.
from tkinter import *
root = Tk()
var = StringVar()
var.set('Select')
def foo(value):
var.set(value)
print("foo1" + value)
def foo2(value):
var.set(value)
print("foo2 " + value)
def foo3(value):
var.set(value)
print("foo3 " + value)
def change_menu(value):
var.set('Select')
print('changing optionmenu commands')
populate_menu(optionmenu, one=foo3, two=foo3)
def populate_menu(optionmenu, **cmds):
menu = optionmenu['menu']
menu.delete(0, "end")
for name, func in cmds.items():
menu.add_command(label=name, command=
lambda name=name, func=func: func(name))
optionmenu = OptionMenu(root, var, ()) # no choices supplied here
optionmenu.pack()
Label(root, textvariable=var).pack()
populate_menu(optionmenu, one=foo, two=foo2, change=change_menu)
root.mainloop()

Trouble with ttk.Entry.selection_present() and ttk.Entry.selection_clear() in tkinter 8.5 and python 3.3

I need entry to contain only one file selection at a time. As it stands now, if the user hits button multiple times to select multiple files (say they selected the wrong file at first or they changed their mind), entry concatenates these multiple filenames all together. Basically, I want entry to contain only the user's last file selection.
Example Code:
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
def browse():
if entry.selection_present() == 1:
entry.selection_clear()
entry.insert(0, filedialog.askopenfilename(parent=frame))
root = Tk()
frame = ttk.Frame(root)
frame.pack()
entry = ttk.Entry(frame, width=100)
entry.pack()
button = ttk.Button(frame, text="Browse", command=browse)
button.pack()
root.mainloop()
Neither entry.selection_present() nor entry.selection_clear() do what I expect. entry.selection_present() always outputs 0, and entry.selection_clear() seems to do nothing.
I was able to get my code to work if I changed the if block to:
if entry.get() != "":
entry.delete(0,1000)
but this seems kind of hackish because the arguments - delete all characters up to 1000 - is arbitrary. What I really want is to clear the entire previous file selection.
Tkinter 8.5 documentation: https://www.tcl.tk/man/tcl8.5/TkCmd/ttk_entry.htm#M23
Use END (or 'end') to denote the end of the entry.
entry.delete(0, END)
Above statement will delete entry content. (from begining(0) to the end).
Alternatively, you can bind the entry with StringVar object, and later call set('') to clear the content.
v = StringVar()
entry = Entry(master, textvariable=v)
# to clear
v.set('')

Python Tkinter one callback function for two buttons

I have been looking around for a long time for answers to this question but still hasn't find anything. I am creating a GUI using Tkinter, and I have two buttons that do mostly the same thing except they receive information from different widgets. One button is for an Entry widget and the other is for a Listbox widget.
The callback function for these two buttons is long (about 200 lines), so I don't want to have separate functions for each button. I have if-statements in the beginning of this callback function to check which button is clicked, and then the codes will take the corresponding value. But I am not sure if the following code shows the right way to do this because apparently it doesn't work perfectly in my program. The callback function would only work for the first time, and if I click the other button I will receive an error. Here is a sample code that I created to illustrate the idea. Note that I want to check if the button is clicked, I do not want to check if the 'value' exists. Please help.
from Tkinter import *
root = Tk()
def DoSomething():
# is this the right way to check which button is clicked?
if button1:
value = user_input.get()
elif button2:
value = choice.get(choice.curselection()[0])
# then more codes that take 'value' as input.
button1 = Button(master,text='Search',command=DoSomething)
button1.pack()
button2 = Button(master,text='Search',command=DoSomething)
button2.pack()
user_input = Entry(master)
user_input.pack()
choice = Listbox(master,selectmode=SINGLE)
choice.pack()
#assume there are items in the listbox, I skipped this portion
root.mainloop()
If you want to pass the actual widget into the callback, you can do it like this:
button1 = Button(master, text='Search')
button1.configure(command=lambda widget=button1: DoSomething(widget))
button2 = Button(master, text='Search')
button2.configure(command=lambda widget=button2: DoSomething(widget))
Another choice is to simply pass in a literal string if you don't really need a reference to the widget:
button1 = Button(..., command=lambda widget="button1": DoSomething(widget))
button2 = Button(..., command=lambda widget="button2": DoSomething(widget))
Another choice is to give each button a unique callback, and have that callback do only the thing that is unique to that button:
button1 = Button(..., command=ButtonOneCallback)
button2 = Button(..., command=ButtonTwoCallback)
def ButtonOneCallback():
value = user_input.get()
DoSomething(value)
def ButtonTwoCallback():
value=choice.get(choice.curselection()[0])
DoSomething(value)
def DoSomething(value):
...
There are other ways to solve the same problem, but hopefully this will give you the general idea of how to pass values to a button callback, or how you can avoid needing to do that in the first place.

Categories