I've looked at several posts on stackOverflow that explain the answer but no matter which I use, I never can get the string from my entry widget; it just detects a string of ""
here's my code:
def buttonTest():
global score
gui.title("Test")
for child in gui.winfo_children():
child.destroy()
global questionText
global questionAnswer
questionText = StringVar()
questionAnswer = 0
question = Label(gui, textvariable = questionText, fg = "black", bg = "white")
question.grid(row = 0, column = 1)
userInput = StringVar()
input = Entry(gui, textvariable = userInput)
input.grid(row = 1, column = 0)
swapQuestion()
checkAns = Button(text = "Check answer", command = partial(checkAnswer, userInput.get(), questionAnswer), fg = "black", width=10)
checkAns.grid(row = 1, column = 2)
Please read and follow this SO help page. Your code is missing lines needed to run and has lines that are extraneous to your question. It is also missing indentation.
Your problem is that you call userInput.get() just once, while creating the button, before the user can enter anything. At that time, its value is indeed ''. You must call it within the button command function, which is called each time the button is pressed.
Here is a minimal complete example that both runs and works.
import tkinter as tk
root = tk.Tk()
user_input = tk.StringVar(root)
answer = 3
def verify():
print(int(user_input.get()) == answer) # calling get() here!
entry = tk.Entry(root, textvariable=user_input)
entry.pack()
check = tk.Button(root, text='check 3', command=verify)
check.pack()
root.mainloop()
Simple example:
from tkinter import *
# Get Entry contents
def print_input():
print(input_variable.get())
window = Tk()
# Create widgets
input_variable = StringVar()
entry_variable = Entry(window, textvariable=input_variable).grid(row=0, column=0)
button_submit = Button(window, text="Submit",command=print_input).grid(row=1, column=0)
window.mainloop()
Where:
input_variable is your variable
entry_variable is the entry box
button_submit calls print_input() to fetch and print the entry_variable's contents which is stored in input_variable
Related
I am building custom Tkinter dialog window with Entry and Combobox. I am stuck with placing text and enter frames. Currently I am placing them manually. I am looking for the way to let tkinter do it automatically (maybe with pack() method). And also configure TopLevel size automatically.
My code:
def ask_unit_len():
values = ['millimeters', 'micrometers', 'nanometers']
top = Toplevel()
top.geometry('170x100')
top.resizable(False, False)
top.focus_set()
top.grab_set()
top.title('Enter length and units')
label_length = Label(top, text='Length:')
label_length.place(x=0, y=0)
units_type = StringVar()
length = StringVar()
answer_entry = Entry(top, textvariable=length, width=10)
answer_entry.place(x=55, y=0)
label_units = Label(top, text='Units:')
label_units.place(x=0, y=30)
combo = Combobox(top, width=10, textvariable=units_type,
values=values)
combo.place(x=50, y=30)
button = Button(top, text='Enter',
command=lambda:
mb.showwarning("Warning",
"Enter all parameters correctly")
if (units_type.get() == "" or not length.get().isdigit()
or int(length.get()) <= 0)
else top.destroy())
button.place(x=65, y=70)
top.wait_window(top)
return int(length.get()), units_type.get()
So, is there any way to perform this?
I've successfully looped the textvariable for all the entries created to point to DoubleVar(), and its working properly. The problem arose when i tried creating reset button for all the entries. from my code as shown, the program runs, doesn't raise any error, and the values in the entries are not cleared. thanks in advance :)
from tkinter import*
root = Tk()
img = PhotoImage(file = 'background.png')
cc = DoubleVar()
cc.set('##')
dr =Label(root, text='helo world')
sd = []
y = -1
dr.pack()
Entry(root, textvariable =cc).pack()
def clear():
cc.set('')
for i in sd:
i['textvariable'] = DoubleVar().set('')
def create():
global y
y +=1
sd.append(Entry(root, width =5))
for i in sd:
i["textvariable"] = DoubleVar()
sd[y].pack()
Button(root, text = 'push', command = clear).pack()
Button(root, text = 'create', command = create).pack()
root.mainloop()
`
Your reset code is creating new DoubleVars, and setting them to the empty string. You're doing nothing to the original variables.
You don't need to use the variables for this, you can simply call the delete method on each entry widget:
for entry in sd:
entry.delete(0, "end")
I am trying to make a GUI text based adventure game in python. I want to be able to take text from a textinput box and store it as string variable.
I have 2 problems:
Making the python wait for the submit button to be pressed, before
processing the input and updating the game.
Getting the text variable out of the command, I would like to not
use global if possible.
Here is some of my code to better understand:
root = tk.Tk()
root.geometry('800x600+100+100')
root.title("my game")
textbox = tk.StringVar()
textboxentry = tk.Entry(root, textvariable=textbox, bd=5, width = "40", font=("times", 20))
textboxentry.pack(in_=bgImageLabel, side = "bottom")
def getInput():
textboxInput = textbox.get() #gets entry
lengthEntry = len(textbox.get())
textboxentry.delete(0,lengthEntry) #removes entry from widget
return textboxInput # I would like this return to work
submit = tk.Button(root, text ="Submit", command = (textboxInput = getInput()))
##I want the command function to use command = getInput and store the return on getInput as textboxInput. This will update the wait_variable down below, and give the inputs(textboxInput) a string to work with.
submit.pack(in_=bgImageLabel, side = "bottom")
while game == True:
root.update_idletasks()
root.update()
submit.wait_variable(textboxentry)
## I need it to wait before proceeding to this next line because i need the textboxInput from the entry widget.
actionInput, extraInput, texts = inputs(textboxInput)
Currently I can't figure a way to use command = (textboxInput = getInput), using lambda or anything else. I just want to store the return which comes off of the Entry as a string variable that can be used by the main function.
All help is appreciated!
Below code processes entry widget's text when Submit button is pressed.
import tkinter as tk
root = tk.Tk()
aVarOutside = 'asd'
def btn_cmd(obj):
#use global variable
global aVarOutside
#print its unmodified value
print("aVarOutside: " + aVarOutside)
#modify it with what's written in Entry widget
aVarOutside = obj.get()
#modify lblTextVar, which is essentially modifying Label's text as lblTextVar is its textvariable
lblTextVar.set(obj.get())
#print what's inside Entry
print("Entry: " + obj.get())
txt = tk.Entry(root)
txt.pack()
lblTextVar = tk.StringVar()
lbl = tk.Label(root, textvariable=lblTextVar)
lbl.pack()
btn = tk.Button(text="Submit", command=lambda obj = txt : btn_cmd(obj))
btn.pack()
root.mainloop()
When the button is pressed:
Value of a global variable, aVarOutside is printed.
Value of aVarOutside is modified to the value of Entry box's
(txt's) content.
Value of a textvariable used by a label (lbl) is modified. Which
means that the text of lbl is updated and can be seen on the GUI.
Finally Entry box, txt's content is printed.
I think you should use inputs() inside getInputs() and then button doesn't have to return any variables - and then you can use root.mainloop() instead of while loop.
import tkinter as tk
# --- functions ---
def inputs(text):
# do something with text
print(text)
# and return something
return 'a', 'b', 'c'
def get_input():
global action_input, extra_input, texts
text = textbox.get()
if text: # check if text is not empty
textbox.set('') # remove text from entry
#textbox_entry.delete(0, 'end') # remove text from entry
action_input, extra_input, texts = inputs(text)
# --- main ---
root = tk.Tk()
textbox = tk.StringVar()
textbox_entry = tk.Entry(root, textvariable=textbox)
textbox_entry.pack()
submit = tk.Button(root, text="Submit", command=get_input)
submit.pack()
root.mainloop()
BTW: you could better organize code
all functions before main part (root = tk.Tk())
PEP8 suggests to use lower_case_names for functions and variables (instead of CamelCaseNames)
global is not prefered method but I think it is better solution than yours.
If you don't need global then you can use classes with self.
import tkinter as tk
# --- classes ---
class Game:
def __init__(self):
self.root = tk.Tk()
self.textbox = tk.StringVar()
self.textbox_entry = tk.Entry(self.root, textvariable=self.textbox)
self.textbox_entry.pack()
self.submit = tk.Button(self.root, text="Submit", command=self.get_input)
self.submit.pack()
def run(self):
self.root.mainloop()
def inputs(self, text):
# do something with text
print(text)
# and return something
return 'a', 'b', 'c'
def get_input(self):
text = self.textbox.get()
if text: # check if text is not empty
self.textbox.set('') # remove text from entry
#textbox_entry.delete(0, 'end') # remove text from entry
self.action_input, self.extra_input, self.texts = self.inputs(text)
# --- functions ---
# empty
# --- main ---
app = Game()
app.run()
I am being particularly obtuse. I am iterating through a list of technical italian words and wanting to insert a translation using a tkinter interface. There is no problem doing this without the GUI: My problem is that I cannot figure out how to do an iteration, load a word into a ttk.Label and wait for a user entry in a ttk.Entry field. I have searched and found explanations, but I am at a loss how to apply the suggestions. This is my code using a trivial list of words:
from tkinter import ttk
import tkinter as tk
def formd():
list_of_terms = ['aardvark', 'ant','zombie', 'cat', 'dog', 'buffalo','eagle', 'owl','caterpiller', 'zebra', 'orchid','arum lily' ]
discard_list = []
temp_dict={}
list_of_terms.sort()
for item in list_of_terms:
listKey.set(item)
# need to wait and get user input
translation =dictValue.get()
temp_dict[item]=translation
discard_list.append(item)
# check if it has worked
for key, value in temp_dict.items():
print(key, value)
# GUI for dict from list
LARGE_FONT= ("Comic sans MS", 12)
root = tk.Tk()
root.title('Nautical Term Bilingual Dictionary')
ttk.Style().configure("mybtn.TButton", font = ('Comic sans MS','12'), padding = 1, foreground = 'DodgerBlue4')
ttk.Style().configure('red.TButton', foreground='red', padding=6, font=('Comic sans MS',' 10'))
ttk.Style().configure('action.TLabelframe', foreground = 'dodger blue3')
#.......contents frames.....................
nb = ttk.Notebook(root)
page5 = ttk.Frame(nb)
# declare variables
listKey= tk.StringVar()
dictValue = tk.StringVar()
# widgets
keyLabel =ttk.Label( page5, text = "key from list", font=LARGE_FONT).grid(row=3, column = 0)
Keyfromlist =ttk.Label(page5, width = 10, textvariable = listKey).grid(row = 3, column = 1)
valueLabel =ttk.Label( page5, text = "enter translation", font=LARGE_FONT).grid(row=3, column = 2)
listValue =ttk.Entry(page5, textvariable =dictValue, width = 15).grid(row = 3, column = 3)
#listValue.delete(0,'end')
#listValue.focus_set()
# add buttons
b1 = ttk.Button(page5, text="add to dictionary",style = "mybtn.TButton", command = formd)
b1.grid(row = 5, column = 0)
b5 = ttk.Button(page5, text="clear entry", style ="mybtn.TButton")
b5.grid(row = 5, column = 2)
nb.add(page5, text='From List')
nb.pack(expand=1, fill="both")
for child in root.winfo_children():
child.grid_configure(padx =5, pady=5)
if __name__ == "__main__":
root.mainloop()
I wonder whether someone could take the time to suggest a solution, please. How to stop a while loop to get input from user using Tkinter? was the one suggestion that I cannot figure how to use in my example
tkinter doesn't "play nice" with while loops.
Fortunately for you, you don't need to use one.
You can do something like the below:
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.list = ['aardvark', 'ant','zombie', 'cat', 'dog', 'buffalo','eagle', 'owl','caterpiller', 'zebra', 'orchid','arum lily' ]
self.text = Label(self.root, text="aardvark")
self.entry = Entry(self.root)
self.button = Button(self.root, text="Ok", command=self.command)
self.text.pack()
self.entry.pack()
self.button.pack()
def command(self):
print(self.text.cget("text")+" - "+self.entry.get())
try:
self.text.configure(text = self.list[self.list.index(self.text.cget("text"))+1])
except IndexError:
self.entry.destroy()
self.button.destroy()
self.text.configure(text = "You have completed the test")
root = Tk()
App(root)
root.mainloop()
This essentially uses the Button widget to iterate to the next text and get the next input.
I am trying to display different images according to a key entered into a tinter entry field. I am returning None from my function to search through the dictionary that holds as key the search word and as value the name of the image. I am not sure how to correct my error. My ultimate goal is to create a tinter GUI that is an 'illustrative' dictionary' Grateful for any help or comments
'''
Example how to place text and image adjacent in a field
'''
from tkinter import *
def choose_image():
library = {'anchor':'admiral.gif', 'hello':'hello_tkinter_cartoon.gif'}
term = e.get()
for desc, image in library.items():
if term == desc:
piccie = image
return desc, piccie
main = Tk()
# enter search key
e = StringVar()
term_entry = Entry( textvariable = e, bd = 2, width = 15, bg = 'mint cream', fg = 'sea green')
term_entry.grid(row =1, column =0, sticky = SE, pady = 15)
butn = Button(text = "Enter",)
butn.grid(column = 1, row = 1, sticky = W)
piccie = choose_image()
print(piccie)
piccie = PhotoImage(file=piccie)
desc = choose_image()
# two results fields adjacent
w1 = Label(main, image =piccie).grid(column = 1, row =0)
w2 = Label(main,
text = desc,
justify=LEFT,
padx = 10).grid(row = 0, column = 0)
if __name__ == '__main__':
main.mainloop()
It returns None because that's the default return value that any function in Python returns.
The first time you call choose_image(), e.get() returns an empty string, thus the following code:
piccie = image
return desc, piccie
will not be executed, because term == desc will not be true.
You can solve this problem for example by returning a default tuple of values when the e.get() returns an empty string:
library = {'anchor':'admiral.gif', 'hello':'hello.gif'}
term = e.get()
if term == "":
return "anchor", "admiral.gif"
Note that in this same function the piccie variable is a local variable to the if block, and not your global variable references a PhotoImage object. On the other hand, you are returning a tuple containing the path to the picture, which should be enough to set the PhotoImage object.
Your second problem is that you are assigning to the attribute file of your PhotoImage object an eventual tuple of strings, but it should only need a string representing the path to the picture:
piccie = choose_image()
piccie = PhotoImage(file=piccie[1])
Note that I am assigning to the file attribute the second element of the tuple.
I don't understand why you are calling the second time choose_image(), you don't need to do it.
Here's the full code with some changes. If you don't understand something, just ask.
from tkinter import *
def choose_image(photo_image, text_lab, image_lab):
library = {'anchor':'admiral.gif', 'hello': 'hello.gif'}
term = e.get()
if term == "":
photo_image.config(file="admiral.gif")
text_lab.config(text="anchor")
image_lab.config(image=photo_image)
else:
for desc, image in library.items():
if term == desc:
photo_image.config(file=image)
text_lab.config(text=desc)
image_lab.config(image=photo_image)
main = Tk()
e = StringVar()
term_entry = Entry(textvariable=e, bd=2, width = 15, bg='mint cream', fg='sea green')
term_entry.grid(row=1, column=0, sticky=SE, pady=15)
label_text = Label(main)
label_text.grid(column=1, row=0)
label_image = Label(main, justify=LEFT, padx=10)
label_image.grid(row=0, column=0)
photo_image = PhotoImage(file="admiral.gif")
choose_image(photo_image, label_text, label_image)
butn = Button(text="Enter", command=lambda: choose_image(photo_image, label_text, label_image))
butn.grid(column=1, row=1, sticky=W)
main.mainloop()
Check also this article:
http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm
Your code is calling choose_image() before the user has a chance to enter anything. You need to wait to call that function until the user has entered something and pressed the enter key, or clicked a button, or something like that.