Convert Tkinter textbox entry into Python Variable - python

(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).

Related

With printing Entry´s text, last character is dismissed. How to fix?

I want to print the text of an Entry each time a new character is written.
By doing this with binding and a command to the widget the last character isn't printed.
I guess that the parameter 'textvariable' is getting updated after binding command had been executed. How to fix this?
from tkinter import *
master = Tk()
var = StringVar()
def execute_e(key):
print(var.get())
E = Entry(master, width=30, textvariable=var)
E.pack()
E.bind('<Key>', execute_e)
It's because the bound event function is being executed before the new key has been added.
Here's a simple workaround that uses the ability to add validation to an Entry widget (the validator accepts any key because it always returns True). The trick is that validator function is set-up to receive the value that the text will have if the change is allowed by specifying the %P when it's configuration as part of the Entry construction via the validatecommand=(validator_command, '%P').
Here's some documentation about adding validation to Entry widgets with details about how it works.
from tkinter import *
master = Tk()
var = StringVar()
def validator(new_value):
print(f'new_value: {new_value}')
return True
validator_command = master.register(validator)
E = Entry(master, width=30, textvariable=var,
validate='key',
validatecommand=(validator_command, '%P'))
E.pack()
master.mainloop()
I feel like this is a question of event handler. When a key is typed, your code first register a key press and execute the bound command execute_e. Only after it has processed this and your event handler has return will it update the entry with the character and proceed to update the tkinter variable.
Your print command therefore comes in before your variable have been updated and you print the previous version of your variable. If you try deleting a character from your entry, you'll see that you get the previous string with the character you have just erased.
The easiest way around that problem for you is probably to bind the command to the tkinter variable rather than the keybind. Do so using trace when the variable is writen like so :
var.trace('w', execute_e)
There are also some methods to manipulate the event handler and decide in which order to execute commands. root.after_idle will execute a command when the code has nothing else to do (when it has computed everything else you asked it to do). Try out this version of your code :
from tkinter import *
master = Tk()
var = StringVar()
def execute_e(*key):
def printy():
print(var.get())
master.after_idle(printy)
E = Entry(master, width=30, textvariable=var)
E.pack()
E.bind('<Key>', execute_e)
master.mainloop()

TypeError: object of type 'Text' has no len()

what is this error and how can i fix it?
def check_number():
if (len(txtNum1)!=11):
error_number = "the number that you entered is wrong"
msg = tk.Message(frame, text = error_number , fg="red")
msg.pack()
title = Label(frame, text="enter your number", fg="gray")
title.pack()
txtNum1 = Text (frame, height=1, width=30)
txtNum1.pack(side=tk.TOP)
button = tk.Button(frame,
text="chek",
fg="green",
command=check_number)
button.pack(side=tk.BOTTOM)
root.mainloop()
i just test __len__method but its not working well.
One of the issues in your code is use use of the if statement. You are asking if the Text Object has a length instead of checking the content of the text object. This can be corrected with the use of get(). If you use get() on a Text Box you will need to specify the indices. .get(1.0, "end"). The problem with doing it this way is you will be getting a length that is 1 character longer than what has been typed so the easy fix to this is to just use an entry field here.
With an Entry() field you can use get() without indices and it will get a copy of the text in that field. Keep in mind if you have a space before or after the text it will count that as well. If you want to compensate for this you can add strip() after get() to delete the white-space on either side.
For a little clean up you will want to change how you are creating your message. With your code if you press the button multiple times then the program will add a new message with each button press. This will cause the messages to stack. To avoid this lets create the message label first and then just update it with our function using the .config() method.
The next bit of clean up lets remove the variable assignments to widgets that do not need them. Your first label and the button do not need to be assigned to a variable in this case.
The last bit of clean up is making sure you are consistent with your widgets. Right now (based of your example code) you are importing tkinter twice. Once with from tkinter import * and once with import tkinter as tk. You do not need both and should stick with the 2nd import method only. Using import tkinter as tk will help prevent you from overriding build in methods on accident.
Take a look at my below code:
import tkinter as tk
root = tk.Tk()
def check_number():
msg.config(text = "")
if len(txtNum1.get().strip()) != 11:
error_number = "the number that you entered is wrong"
msg.config(text = error_number)
tk.Label(root, text="enter your number", fg="gray").pack()
txtNum1 = tk.Entry(root, width=30)
txtNum1.pack(side=tk.TOP)
tk.Button(root, text="chek", fg="green", command=check_number).pack(side=tk.BOTTOM)
msg = tk.Message(root, text = "" , fg="red")
msg.pack()
root.mainloop()

How to create entry inputs in a toplevel window

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))

Getting a TKinter input stored into a string variable in the next function?

I am new to TKinter and I am not able to figure out how to store the input from a textbox in TKINTER. I've tried following virtually every tutorial and looked at similar posts but their ideas arent fixing my issue :/.
def cityInfoWindow(self, flightMap):
infoWindow = Tk()
infoWindow.geometry("500x500+100+100")
infoWindow.title("CSAir-City Information")
global input
input = StringVar()
cityEntry = Entry(infoWindow,textvariable = input).pack()
okButton = Button(infoWindow, text = 'Submit', command = lambda:self.getCityInfo(infoWindow, input)).pack()
def getCityInfo(self, infoWindow, input):
content = input.get()
print content
return
Ive tried passing in my input into my function but that doesnt work.
There is built-in function named input, try not to use it as a variable name. Other than that, it is pretty straight-forward,
You assign a Variable Class of your choice (StringVar() in here) for Entry then get content of said variable any time you want with get() method.
Also there is a get() method for Entry. With that, you can get content of Entry without using StringVar.
Below is a simple example showing how to do it. You should implement it to your code yourself.
import tkinter as tk
def get_class(): #no need to pass arguments to functions in both cases
print (var.get())
def get_entry():
print (ent.get())
root = tk.Tk()
var = tk.StringVar()
ent = tk.Entry(root,textvariable = var)
btn1 = tk.Button(root, text="Variable Class", command=get_class)
btn2 = tk.Button(root, text="Get Method", command=get_entry)
ent.pack()
btn1.pack()
btn2.pack()
root.mainloop()
EDIT: By the way, next time when you post a question, please consider adding the full traceback or what went wrong (what did you expect and what did you get etc..) instead of saying "it is not working" only. With that, you will probably get more help with more precise answers.

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