I am new to codding in general. I have found a code for a function which restricts users of entering anything but digits in entry field but I can't assign the function to entry object.
I have tree problems.
I can't assign function to entry.
I want error print message to show in label "A".
Pressing "Enter" multiple times execute "def doit(FFF)" multiple times on top of each other, so I want to restrict pressing it more than one time.
I have been trying for the past 3 days but I keep failing.
from tkinter import *
def doit(FFF):
...
def val():
API = IN.get()
while True:
try:
API = int(input())
except ValueError:
print('Not an integer')
continue
else:
return API
break
root = Tk()
root.geometry("300x200")
IN = Entry(root)
IN.bind("<Return>", val, lambda _:doit(FFF))
IN.pack(side=LEFT, fill="both", expand=True)
A = Label(root, fg="red")
A.pack(side=LEFT)
B = Button(root, text="START", fg="black", command=lambda:doit(FFF))
B.pack(side=RIGHT)
root.mainloop()
Example
is_integer() checks only if text is integer number and returns True/False so it can be used in many places.
<KeyRelease> executes validate() after every keypress (or rather key release) and validate() uses is_integer() to check text in Entry (event.widget gives access to widget to which was bind() event) and changes text in Label.
Button executes function run_it() which uses is_integer() to check if Entry has correct integer (to make sure) or you have to check if Entry is not empty. If Entry has no correct integer then it changes text in Label and ends function.
import tkinter as tk
# --- functions ---
def run_it():
# you can check it again to make sure
text = e.get()
if not is_integer(text):
l['text'] = "You can't run it"
return
# do what you want
l['text'] = 'Running ...'
def validate(event):
#text = e.get()
text = event.widget.get()
if is_integer(text):
l['text'] = ''
else:
l['text'] = 'Not an integer'
def is_integer(text):
try:
value = int(text)
return True
except ValueError:
return False
# --- main ---
root = tk.Tk()
e = tk.Entry(root)
e.pack()
#e.bind("<Return>", validate)
e.bind("<KeyRelease>", validate)
l = tk.Label(root)
l.pack()
b = tk.Button(root, text="START", command=run_it)
b.pack()
root.mainloop()
Related
Hello this is my first question on this platform. I got a problem with tkinter, I have an entry where the user can write a number. If the user writes something else and press save a label appears with "only floats allowed" so far so good. But if the user writes after the label a appears a number an presses yes, the label should be deleted. How can I delete the label after it plots the first time by correcting the entry and pressing save again?
P.s. its my first try to Code a GUI so I'm thankful for other tipps & tricks.
import tkinter as tk
parison_window = tk.Tk()
parison_window.title("Create Parison")
parison_window.geometry("1000x1000")
pwt1_lbl = tk.Label(parison_window, text="PWT1")
pwt1_lbl.pack()
pwt1_lbl.place(x=30, y=130)
label = tk.Label(parison_window, text="1")
label.pack()
label.place(x=10, y=140 + 20 )
entry = tk.Entry(parison_window, width=5, justify="center")
entry.pack()
entry.place(x=30, y=140 + 20)
def check_and_save():
if entry.get():
try:
pwt1 = float(entry.get())
except ValueError:
error_text = tk.Label(parison_window, text="only floats allowed")
error_text.pack()
error_text.place(x=150, y=140 + 20 )
save_button = tk.Button(parison_window, text="save", command=check_and_save)
save_button.pack()
parison_window.mainloop()
If you want to remove text from existing label then you can use error_text.config(text="") or error_text["text"] = "".
If you want to remove all widget then you may do error_text.destroy()
But all this make problem because widget may not exists in some moments and trying to set text or destroy it may generate error.
You should rather create empty label at start and later only replace text in this label.
import tkinter as tk
# --- functions --- # PEP8: all functions before main code
def check_and_save():
if entry.get():
try:
pwt1 = float(entry.get())
error_text['text'] = ""
except ValueError:
error_text['text'] = "only floats allowed"
# --- main ---
parison_window = tk.Tk()
parison_window.title("Create Parison")
parison_window.geometry("1000x1000")
pwt1_lbl = tk.Label(parison_window, text="PWT1")
pwt1_lbl.place(x=30, y=130)
# ---
label = tk.Label(parison_window, text="1")
label.place(x=10, y=140+20)
entry = tk.Entry(parison_window, width=5, justify="center")
entry.place(x=30, y=140+20)
error_text = tk.Label(parison_window) # create label with empty text
error_text.place(x=150, y=140+20)
# ---
save_button = tk.Button(parison_window, text="save", command=check_and_save)
save_button.pack()
parison_window.mainloop()
PEP 8 -- Style Guide for Python Code
BTW:
pack() and place() (and grid()) are different layout managers and when you use place() then you don't need pack() (and grid())
EDIT:
Using destroy() it would need to use global variable error_text with default value None at start. And later it would need to check if error_text is not None and destroy it (and assign again None)
import tkinter as tk
# --- functions --- # PEP8: all functions before main code
def check_and_save():
global error_text # inform function to assign new value to global variable `error_text` instead of creating local variable `error_text`
if entry.get():
try:
pwt1 = float(entry.get())
if error_text is not None:
error_text.destroy()
error_text = None
except ValueError:
if error_text is not None:
error_text.destroy()
error_text = None
error_text = tk.Label(parison_window, text="only floats allowed")
error_text.place(x=150, y=140+20)
# --- main ---
parison_window = tk.Tk()
parison_window.title("Create Parison")
parison_window.geometry("1000x1000")
pwt1_lbl = tk.Label(parison_window, text="PWT1")
pwt1_lbl.place(x=30, y=130)
# ---
label = tk.Label(parison_window, text="1")
label.place(x=10, y=140+20)
entry = tk.Entry(parison_window, width=5, justify="center")
entry.place(x=30, y=140+20)
error_text = None # global variable with default value
# ---
save_button = tk.Button(parison_window, text="save", command=check_and_save)
save_button.pack()
parison_window.mainloop()
`enter code here`
from tkinter import *
from tkinter.ttk import *
def on_field_change(index, value, op):
choice=StringVar
print( "combobox updated to ", c.get() ) # does print the updated values
#choice=c.get
#return(choice) # added a return for testing - not useful
chosen=StringVar
chosen=""
root = Tk()
root.geometry("400x200+10+10")
v = StringVar()
x = StringVar
chosen=StringVar
chosen=""
c = Combobox(root, textvar=v, values=["foo", "bar", "baz"])
c.set('foog')
c.grid(row=0, column=1)
#choice_label = ttk.Label(text='choice='+c.get() ) #does not update
choice_label = Label(text= c.get ) #does not update
choice_label = Label(text= v ) #does not update
choice_label.grid(row=3, column=0)
quit_button = ttk.Button(root, text="QUIT")
quit_button.grid(row=4, column=0)
quit_button['command'] = root.destroy
v.trace('w',on_field_change)
print('the new v is : ', c.get()) # does not print updated values
#x=v.trace('w',on_field_change)
#print('the new choice is : ', x ) # does not print updated values
# try to use the selected item in another label and for a dictionary search
mainloop()
enter code here
Multiple examples of binding an event handler to the combo box. Almost all just print the selected value from the event handler.
Other approaches trace a string variable to the event handler.
I can’t figure how to get the returned value into the main body. My goal would be to use it to become the text of a label and also be an index or key in a dictionary.
Advice appreciated.
I keep getting this issue in my code when I try to use the retrieve command that I had made, I want the button named 'retrieve' to get the information in the entry box. This will then trigger the strGame command.
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 1699, in __call__
return self.func(*args)
TypeError: retrieve() missing 1 required positional argument: 'entry'
My code:
from tkinter import *
verif = False
true=True
items=['pistol','knife','sword']
command=False
root=Tk()
root.iconbitmap('GameLogo.ico')
strvar=StringVar()
root.title('RPG Game')
root.geometry('900x600')
root.resizable(False,False)
frame1 = Frame(root, relief=RAISED)
frame1.pack(side=LEFT, fill=Y, padx=10, pady=10)
entry = Entry(frame1).pack(fill=X)
def retrieve(entry):
result=entry.get()
return result
retreive = Button(frame1, command=retrieve, text="Click to input").pack(fill=X)
def srtGame():
try:
if retrieve(e1)==str('drop'):
print("HELLO")
command = True
print ("Your inventory:", items)
dropItem = input("Which item do you want to drop? ")
for i in range(len(items)):
if items[i] == dropItem:
items.remove(dropItem)
print("Your", dropItem,"has been dropped. ")
print("Your inventory", items)
verif = True
if verif == False and command == True:
print("You don't have that item. Please enter another command.")
except:
IndexError
StartGame = Button(frame1, text="Start game.", relief=RAISED, command=srtGame).pack(fill=X)
GameOutput = Label(frame1, textvariable=strvar, relief=RAISED).pack(fill=X)
root.mainloop()
There are numerous errors in this program, which I will clarify here.
Useless variable assignments
The lines that goes like:
widgetVar = Widget(args).geometry(args)
Such as:
entry = Entry(frame1).pack(fill=X)
retreive = Button(frame1, command=retrieve, text="Click to input").pack(fill=X)
Is surely not doing what you intended. By chaining the construction of the widget along with geometry call, what really happens is: Widget(...) returns an instance, on which pack() or other geometry manager is called, that in turn returns None.
Hence all these variables are None, and if you need to store a reference you should break it down to two different lines of code.
Unnecessary "middlemen"
As I understand, you want your game to start (probably load another window/screen) on clicking Start game.
You can just add code to check the Entry contents when the user presses Start game directly, instead of having a button to Input that really does nothing useful as such.
Understand Tkinter vars
The point of using Tkinter vars is to avoid explicitly accessing the Widget to check data that it contains. For example, if you bind StringVar to the Entry, you no longer need to access the Entry object directly.
Mixing command-line and GUI
I would recommend using the Dialog in Tkinter, that can be used to create a pop-up with a text field, to ask the user for which item to drop.
Working Code
from Tkinter import *
items = ['pistol', 'knife', 'sword']
root = Tk()
strvar = StringVar()
root.title('RPG Game')
root.geometry('900x600')
root.resizable(False, False)
frame1 = Frame(root, relief=RAISED)
frame1.pack(side=LEFT, fill=Y, padx=10, pady=10)
entry = Entry(frame1, textvariable=strvar)
entry.pack(fill=X)
def srtGame():
if strvar.get() == str('drop'):
print("HELLO")
print("Your inventory:", items)
# TODO:
# Use Dialog window to ask for item to drop
# Let that be stored in `dropItem`
dropItem = None # Temporary
# Better than using for loop for this
if dropItem in items:
items.remove(dropItem)
print("Your", dropItem, "has been dropped. ")
print("Your inventory", items)
else:
print("You don't have that item. Please enter another command.")
startButton = Button(
frame1, text="Start game.", relief=RAISED, command=srtGame)
startButton.pack(fill=X)
GameOutput = Label(frame1, textvariable=strvar, relief=RAISED)
GameOutput.pack(fill=X)
root.mainloop()
On the Forum there has recently been posted a Question by #Clueless_captain; it was answered by #furas. I am new to stackoverflow so I can not comment in that Conversation. This is the URL to that Conversation: (Tkinter Entry widget stays empty in larger programs (Python 2)). The Code posted by furas is not exactly what I try to do, but the only Thing I can not do myself is finding a way to re-use the Input that has been given in the EntryWidget. I modified the Code written by furas; my Goal was that the Input would be printed before the GUI terminated. For that I bound the Return key to a new Function, this Function was supposed to get the Textstring in this new Function where it would further be processed. It does only do that when I click the Button to get a name for a second time. Is the order of this Code off? I believe the Issue is closely related to the String 'e.bind' on line ten, but I can not find the Issue.
Best Regards, G_Lehmann
---------- The modified code:
from Tkinter import *
def get_input(text, variable):
win = Toplevel()
win.title("Get value")
f = LabelFrame(win, text=text)
f.pack()
e = Entry(win, textvariable=variable)
e.bind("<Return>", do_more(text, variable, e))
e.pack(side="right")
#I tried e.bind here, but This had no Effect.
b = Button(win, text = "Cancel", command=win.destroy)
b.pack()
#do_more is the new Function I want to use to process the Variable 'data' further.
def do_more(text, variable, e):
data = e.get()
print data
print len(data)
print type(data)
def get_value(text, variable):
get_input(text, variable)
# --- main --
root = Tk()
root.title("Ask-name-SUB")
# global variables
var_name = StringVar()
var_address = StringVar()
b = Button(root, text="Enter your name", command=lambda: get_value("Your name:", var_name))
b.pack()
b = Button(root, text="Enter your address", command=lambda: get_value("Your address:", var_address))
b.pack()
b = Button(root, text="Cancel", command=root.destroy)
b.pack()
root.mainloop()
# --- after -- (My Edit: I disabled this as I want to bind the Variables before my GUI gets terminated)
"""
name = var_name.get()
print "Print name, its length, its type"
print name, len(name), type(name)
address = var_address.get()
print "Print address, its length, its type"
print address, len(address), type(address)
"""
bind expects function name (like in command=) so you have to use lambda to assign function with arguments. Besides bind execute function with argument event so you have to receive it.
e.bind("<Return>", lambda event:do_more(variable))
You can assign do_more to button too
b = Button(win, text="OK", command=lambda:do_more(variable))
and do the same with Return and with Button - and close window after do something with variable.
You can also do the same in get_value after you close window but you have to use win.wait_window() because normally tkinter create window and doesn't wait till you close it.
So now you have two possibility to do something with value - in do_more or in get_value - choose one. Both method can be modify - ie. you can use class and create own dialog window.
from Tkinter import *
# --- ---
# global variable to use in different functions
win = None
def get_input(text, variable):
global win # inform function to use global variable `win` to assign value
win = Toplevel()
win.title("Get value")
f = LabelFrame(win, text=text)
f.pack()
# use `f` instead of `win` to put inside LabelFrame
e = Entry(f, textvariable=variable)
e.pack()#side="right")
e.bind("<Return>", lambda event:do_more(variable))
b = Button(win, text="OK", command=lambda:do_more(variable))
b.pack()
def do_more(variable):
data = variable.get()
print 'do_more:', data, len(data), type(data)
win.destroy()
# --- ---
def get_value(text, variable):
# create window
get_input(text, variable)
# this code is executed directly after creating window, not after closing window
# so code has to wait till window is closed
win.wait_window()
data = variable.get()
print 'get_value:', data, len(data), type(data)
# --- main --
root = Tk()
root.title("Ask-name-SUB")
# global variables
var_name = StringVar()
var_address = StringVar()
b = Button(root, text="Enter your name", command=lambda:get_value("Your name:", var_name))
b.pack()
b = Button(root, text="Enter your address", command=lambda:get_value("Your address:", var_address))
b.pack()
b = Button(root, text="Cancel", command=root.destroy)
b.pack()
root.mainloop()
I am new to Tkinter and not to sure how to proceed. I am trying to link a function that I define to a entry widget that is activated by a button. but I can't figure out how to get the three to communicate to each other. I would like it to print as well as return to the script so that I can be used in another function. This is what I have so far:
import Tkinter as tk
def TestMath(x):
calculate = x + 4
print calculate
return calculate
root = tk.Tk()
entry = tk.Entry(root)
value = entry.get()
number = int(value)
button = tk.Button(root, text="Calculate")
calculation = TestMath(number)
root.mainloop()
Button calls function assigned to command= (it has to be "function name" without () and arguments - or lambda function)
TestMath assigns calculation to global variable result and other functions can have access to that value.
import Tkinter as tk
def TestMath():
global result # to return calculation
result = int(entry.get())
result += 4
print result
result = 0
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
button = tk.Button(root, text="Calculate", command=TestMath)
button.pack()
root.mainloop()
Function called by button don't have to return value because there is no object which could receive that value.