Getting the empty string from entry textbox instead of value entered - python

I have created a textbox in a tkinter window which is called by a button.
I want to get the value of textbox in another window on clicking a button.
But when i print the value on console, it prints an empty string instead of the value entered in textbox.
from tkinter import *
def click():
print(id.get())
def submit():
win2=Tk()
Label1=Label(win2,text='Id').pack()
global id
id=StringVar()
textbox=Entry(win2,textvariable=id).pack()
btn2=Button(win2,text='Click',command=click).pack()
win1=Tk()
btn1=Button(win1,text='Submit',command=submit).pack()
Please check my code.

You might want to try something like this:
import tkinter as tk
class MainPage(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.btn1 = tk.Button(self, text='Submit', command=self.submit)
self.btn1.pack()
def submit(self):
self.win2 = tk.Tk()
self.Label1 = tk.Label(self.win2, text='Id')
self.Label1.pack()
self.id = tk.StringVar()
self.textbox = tk.Entry(self.win2, textvariable=self.id)
self.textbox.pack()
self.btn2 = tk.Button(self.win2, text='Click', command=self.click)
self.btn2.pack()
def click(self):
print(self.textbox.get())
interface = MainPage()
interface.mainloop()
Edit: The main difference with the original code is that the print calls the Entry widget, rather than the StringVar. If you would like to set the StringVar to the text inserted in the textbox, then you would have to call at some point
self.id.set(self.textbox.get())
then the self.id.get() would return what you expect.

From previous answer by #neko,i got an answer similar to my code:
from tkinter import *
def click():
print(textbox.get())
def submit():
win2=Tk()
Label1=Label(win2,text='Id').pack()
global textbox
id=StringVar()
textbox=Entry(win2,textvariable=id)
textbox.pack()
btn2=Button(win2,text='Click',command=click).pack()
win1=Tk()
btn1=Button(win1,text='Submit',command=submit).pack()
The problem was that i was using id.get(), which is not working in multiple tkinter window. So now i used textbox.get() which is working fine here.

Have you tried to do this? :
print(id.get("1.0",'end-1c'))
The '1.0' part tells the method to start reading at the first line (starting with the first character, because of the 0). The 'end-1c' argument tells the method to read until it reaches the end of the text. Note that 1c removes 1 character from the text, because if you used just 'end', it would add a new line character at the end of your text.

Related

display not changing despite variables being changed on tkinter

I want to write a program where after a user enters text and clicks a button, the text becomes a label and the button text is changed. My code is:
# Imports
import os, sys
import tkinter
"""
Tkinter program 1
text box + button + label
"""
# Button Entry
def enter(inputtedinfo, randvar, EnterMessage):
randvar = inputtedinfo.get()
EnterMessage = "Submitted!"
# Main Function
def main():
something = tkinter.Tk()
something.title("My First Tkinter Window")
something.geometry("600x400")
randvar = ""
EnterMessage = "Enter"
inputtedinfo = tkinter.StringVar()
userLabel = tkinter.Label(something, text = randvar)
userEntry = tkinter.Entry(something, textvariable = inputtedinfo)
userButton = tkinter.Button(something, text = EnterMessage, command = enter(inputtedinfo, randvar, EnterMessage))
userEntry.grid(row=0,column=0)
userLabel.grid(row=0,column=1)
userButton.grid(row=0,column=2)
something.mainloop()
sys.exit(0)
if(__name__ == "__main__"):
main()
The user input works, but clicking the button does nothing despite the fact that it is supposed to change the variables for the button and label displays. Did I mess up somewhere?
The command argument takes the name of a function. If you write the complete call with arguments, it's not the name of the function but whatever is returned by this exact function call. So, your button will not work. It will have the command None.
In order to do what you want to do, you have to make the StringVar()s accessible to the function you are calling. So, you can both get the contents of the entry and change the values of the button and the label. To do this, best add the string variables and the widgets as attributes to the toplevel you already created (something). So, they stay available to all functions and you can get and change information:
# Button Entry
def enter():
something.randvar.set(something.inputtedinfo.get())
something.userButton["text"] = "Submitted!"
# Main Function
def main():
global something
something = tkinter.Tk()
something.title("My First Tkinter Window")
something.geometry("600x400")
something.randvar = tkinter.StringVar()
something.randvar.set("")
EnterMessage = "Enter"
something.inputtedinfo = tkinter.StringVar()
userLabel = tkinter.Label(something, textvariable = something.randvar)
something.userEntry = tkinter.Entry(something, textvariable = something.inputtedinfo)
something.userButton = tkinter.Button(something, text = EnterMessage, command = enter)
something.userEntry.grid(row=0,column=0)
userLabel.grid(row=0,column=1)
something.userButton.grid(row=0,column=2)
something.mainloop()
if(__name__ == "__main__"):
main()
There are few issues in your code:
assign string to textvariable, should use StringVar instead
command=enter(...) will execute enter(...) immediately and then assign None to command option, should use lambda instead
updating strings inside enter() does not automatically update the label and the button, should use .set() on the StirngVar instead
Below is modified code:
def enter(inputtedinfo, randvar, EnterMessage):
# used .set() to update StringVar
randvar.set(inputtedinfo.get())
EnterMessage.set("Submitted!")
def main():
something = tkinter.Tk()
something.title("My First Tkinter Window")
something.geometry("600x400")
randvar = tkinter.StringVar() # changed to StringVar()
EnterMessage = tkinter.StringVar(value="Enter") # changed to StringVar()
inputtedinfo = tkinter.StringVar()
userLabel = tkinter.Label(something, textvariable=randvar) # used textvariable instead of text option
userEntry = tkinter.Entry(something, textvariable=inputtedinfo)
userButton = tkinter.Button(something, textvariable=EnterMessage, command=lambda: enter(inputtedinfo, randvar, EnterMessage))
userEntry.grid(row=0,column=0)
userLabel.grid(row=0,column=1)
userButton.grid(row=0,column=2)
something.mainloop()

How can i get input text from an entrybox in Tkinter? [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 2 years ago.
So i am trying to get an text input for my program but tkinter doesn't seem to register it,
and i don't know what i have done wrong
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
My code looks something like this. Everything else is working the self.newWindow(value) is just
a function that creates a new window from the main one
so i said text=e1.get() but i ran the debbuger and it says it is an empty string and i want to pass this text through the function passValue()(a function that passes the value to the controller), i used button.bind() to do that. Is that ok?
I tested it by putting a default value at text like text="My name" and it did pass the value so that should be in order but i don't know why doesn't it get it from the entry box like it should.
I even tried to do e1.insert(0,"some random thing") and text= e1.get() and it did get it so i think there's a problem with the input.
Do i need to use some special kind of input function?
The whole code:
class Gui:
def __init__(self, controller):
self.main = tk.Tk()
self.main.title("DSA Quiz Helper")
self.__controller = controller
def IntFixPostExecute(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
self.IntfixPostfixWindow(value)
def mainWindow(self):
self.main.geometry("800x500")
# to do scrollbar
lb = tk.Listbox(self.main, width=50, height=30)
lb.insert(1, "Intfix and Postfix Calculator")
lb.insert(2, "Something else")
lb.bind("<Double-Button-1>", self.IntFixPostExecute)
lb.pack()
def IntfixPostfixWindow(self, value):
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
print(text)
def passValue(self, rezultat, value):
returnValue = self.__controller.InfixToPostC(rezultat, value)
rezultat.insert(tk.INSERT, returnValue)
def newWindow(self, msg):
newwind = tk.Toplevel(self.main)
q1 = tk.Frame(newwind)
q1.pack()
newwind.geometry("500x230")
return newwind
def run(self):
self.mainWindow()
self.main.mainloop()
if i set this manually it works. I don't understand why i doesn't work from entrybox input
text = tk.StringVar()
e1 = tk.Entry(window, textvariable=text)
text.set("x+y*2")
text = e1.get()
e1.place(x=0, y=50)
I think i figured it out (correct me if i am wrong). I think there is a problem
with the button because as soon as a newwindow is open, the button automatically clicks itself, when at first in the entry box there is no text written yet(so it sends to the controller with the initial text(which is empty)). The problem is why the button auto-clicks itself( or anyway auto-runs the function passValue) and why after i input the text and click the button again it does nothing(so as i understand it works only one time and auto-runs itself, at first there is no text in entrybox and the button auto-runs itself,therefore passing an empty string
You should use entryname.get() to get the text that is inside that entry instead of declaring stringVar() and making that much more unreadable and hard to comprehend and to work with. But this is my point of view! – Tiago Oliveira 48 mins ago
I think what is happening is that u use the method right after declaring the entry widget wich means u are going to get a "" empty string because that's nothing that was written there, u need to replace on the command parameter with entryname.get() instead of declaring variable = entryname.get() and passing that as parameter wich will always be empty! Hope this helps!

Python - Making a button change position randomly

I need to be able to change the button position when I click on it. The position changes by a random amount each time I click on it. But all i get is an error. Here's my code:
from tkinter import *
from random import randrange
class Window(Frame):
def position(self):
return randrange(0,400),randrange(0,300)
def __init__(self,master=None):
Frame.__init__(self,master)
self.master = master
self.__init__window()
def __init__window(self):
self.master.title("GUI")
self.pack(fill=BOTH, expand=1)
Button1 = Button(self, text="Click me if you can",command=self.Message)
Button1.place(*position())
menu=Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
file.add_command(label="Exit", command=self.client_exit)
menu.add_cascade(label="File",menu=file)
edit = Menu(menu)
edit.add_command(label="Show text", command=self.showText)
menu.add_cascade(label="Edit", menu=edit)
def Message(self):
print("Hello world")
def showText(self):
text = Label(self, text="Hey there!")
text.pack()
def client_exit(self):
exit()
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
"Button1.place" is the position of the button that needs to be changed but I am completely clueless how else to do this. I used variables as well.
It seems place() wants keyword arguments. You can let the function position() return a dict and unpack it in the place() statement:
def position(self):
return {'x':randrange(0,400),'y':randrange(0,300)}
Placing the button with:
self.Button1.place(**self.position())
You also need to prefix the button name with "self" to be able to access it from outside the function __init__window().
Then simply add a copy of the place() statement in the button callback function:
def Message(self):
print("Hello world")
self.Button1.place(**self.position())
That works fine for me at least (Python 3.6.5 under win10).
You'll have to reduce the random values generated for x and y or parts of the button will occationally be outside the window...

Python3 Print Tuple in another class [duplicate]

I am trying to set the text of an Entry widget using a button in a GUI using the tkinter module.
This GUI is to help me classify thousands of words into five categories. Each of the categories has a button. I was hoping that using a button would significantly speed me up and I want to double check the words every time otherwise I would just use the button and have the GUI process the current word and bring the next word.
The command buttons for some reason are not behaving like I want them to. This is an example:
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
v = tk.StringVar()
def setText(word):
v.set(word)
a = ttk.Button(win, text="plant", command=setText("plant"))
a.pack()
b = ttk.Button(win, text="animal", command=setText("animal"))
b.pack()
c = ttk.Entry(win, textvariable=v)
c.pack()
win.mainloop()
So far, when I am able to compile, the click does nothing.
You might want to use insert method. You can find the documentation for the Tkinter Entry Widget here.
This script inserts a text into Entry. The inserted text can be changed in command parameter of the Button.
from tkinter import *
def set_text(text):
e.delete(0,END)
e.insert(0,text)
return
win = Tk()
e = Entry(win,width=10)
e.pack()
b1 = Button(win,text="animal",command=lambda:set_text("animal"))
b1.pack()
b2 = Button(win,text="plant",command=lambda:set_text("plant"))
b2.pack()
win.mainloop()
If you use a "text variable" tk.StringVar(), you can just set() that.
No need to use the Entry delete and insert. Moreover, those functions don't work when the Entry is disabled or readonly! The text variable method, however, does work under those conditions as well.
import Tkinter as tk
...
entry_text = tk.StringVar()
entry = tk.Entry( master, textvariable=entry_text )
entry_text.set( "Hello World" )
You can choose between the following two methods to set the text of an Entry widget. For the examples, assume imported library import tkinter as tk and root window root = tk.Tk().
Method A: Use delete and insert
Widget Entry provides methods delete and insert which can be used to set its text to a new value. First, you'll have to remove any former, old text from Entry with delete which needs the positions where to start and end the deletion. Since we want to remove the full old text, we start at 0 and end at wherever the end currently is. We can access that value via END. Afterwards the Entry is empty and we can insert new_text at position 0.
entry = tk.Entry(root)
new_text = "Example text"
entry.delete(0, tk.END)
entry.insert(0, new_text)
Method B: Use StringVar
You have to create a new StringVar object called entry_text in the example. Also, your Entry widget has to be created with keyword argument textvariable. Afterwards, every time you change entry_text with set, the text will automatically show up in the Entry widget.
entry_text = tk.StringVar()
entry = tk.Entry(root, textvariable=entry_text)
new_text = "Example text"
entry_text.set(new_text)
Complete working example which contains both methods to set the text via Button:
This window
is generated by the following complete working example:
import tkinter as tk
def button_1_click():
# define new text (you can modify this to your needs!)
new_text = "Button 1 clicked!"
# delete content from position 0 to end
entry.delete(0, tk.END)
# insert new_text at position 0
entry.insert(0, new_text)
def button_2_click():
# define new text (you can modify this to your needs!)
new_text = "Button 2 clicked!"
# set connected text variable to new_text
entry_text.set(new_text)
root = tk.Tk()
entry_text = tk.StringVar()
entry = tk.Entry(root, textvariable=entry_text)
button_1 = tk.Button(root, text="Button 1", command=button_1_click)
button_2 = tk.Button(root, text="Button 2", command=button_2_click)
entry.pack(side=tk.TOP)
button_1.pack(side=tk.LEFT)
button_2.pack(side=tk.LEFT)
root.mainloop()
Your problem is that when you do this:
a = Button(win, text="plant", command=setText("plant"))
it tries to evaluate what to set for the command. So when instantiating the Button object, it actually calls setText("plant"). This is wrong, because you don't want to call the setText method yet. Then it takes the return value of this call (which is None), and sets that to the command of the button. That's why clicking the button does nothing, because there is no command set for it.
If you do as Milan Skála suggested and use a lambda expression instead, then your code will work (assuming you fix the indentation and the parentheses).
Instead of command=setText("plant"), which actually calls the function, you can set command=lambda:setText("plant") which specifies something which will call the function later, when you want to call it.
If you don't like lambdas, another (slightly more cumbersome) way would be to define a pair of functions to do what you want:
def set_to_plant():
set_text("plant")
def set_to_animal():
set_text("animal")
and then you can use command=set_to_plant and command=set_to_animal - these will evaluate to the corresponding functions, but are definitely not the same as command=set_to_plant() which would of course evaluate to None again.
One way would be to inherit a new class,EntryWithSet, and defining set method that makes use of delete and insert methods of the Entry class objects:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
class EntryWithSet(tk.Entry):
"""
A subclass to Entry that has a set method for setting its text to
a given string, much like a Variable class.
"""
def __init__(self, master, *args, **kwargs):
tk.Entry.__init__(self, master, *args, **kwargs)
def set(self, text_string):
"""
Sets the object's text to text_string.
"""
self.delete('0', 'end')
self.insert('0', text_string)
def on_button_click():
import random, string
rand_str = ''.join(random.choice(string.ascii_letters) for _ in range(19))
entry.set(rand_str)
if __name__ == '__main__':
root = tk.Tk()
entry = EntryWithSet(root)
entry.pack()
tk.Button(root, text="Set", command=on_button_click).pack()
tk.mainloop()
e= StringVar()
def fileDialog():
filename = filedialog.askopenfilename(initialdir = "/",title = "Select A
File",filetype = (("jpeg","*.jpg"),("png","*.png"),("All Files","*.*")))
e.set(filename)
la = Entry(self,textvariable = e,width = 30).place(x=230,y=330)
butt=Button(self,text="Browse",width=7,command=fileDialog).place(x=430,y=328)

delete buttons defined in other function

I'm trying to get a button to dissapear when you click it, and other buttons to appear. Then when the "back" button is clicked, I want the newer buttons to dissapear again, and the original button to appear again.
The problem is that I don't know how to make a function retrieve information from another function. If I try to do anything to the search_button in the search(event) function, the search_button is not defined because it was only defined in the main() function.
import tkinter as tk
window = tk.Tk()
def search(event):
#insert "delete search_button" logic here
easy_button = tk.Button(window, text = "Easy")
easy_button.bind("<Button-1>", easy_search)
easy_button.pack()
back_button = tk.Button(window, text = "Back")
back_button.bind("<Button-1>", back_button1) #had to put 1 on end here. It seems back_button is predefined as an object
back_button.pack()
def easy_search(event):
#does a bunch of stuff that doesn't matter for this question
pass
def back_button1(event):
#this should delete easy_button and reinitiate search_button
pass
def main():
search_button = tk.Button(window, text = "Search")
search_button.bind("<Button-1>", search)
search_button.pack()
main()
window.mainloop()
The easiest way is to make everything into a class, in which all your functions could share the same self namespace. And that if you want to bind the button pressed with another function, use 'command' instead, unless you're actually using the event.
That will come together to this:
import tkinter as tk
window = tk.Tk()
class Search:
def __init__(self):
self.search_button = tk.Button(window, text = "Search")
self.search_button['command'] = self.search
self.search_button.pack()
def search(self):
self.search_button.pack_forget() # or .destroy() if you're never going to use it again
self.easy_button = tk.Button(window, text = "Easy")
self.easy_button['command'] = self.easy_search
self.easy_button.pack()
self.back_button = tk.Button(window, text = "Back")
self.back_button['command'] = self.back_button1
self.back_button.pack()
def easy_search(self):
#does a bunch of stuff that doesn't matter for this question
pass
def back_button1(self):
#this should delete easy_button and reinitiate search_button
pass
widgets = Search()
window.mainloop()
There you can call the widget's destroy or pack_forget command.

Categories