validation of tkinter entry widget [duplicate] - python

This question already has answers here:
Interactively validating Entry widget content in tkinter
(10 answers)
Closed 3 years ago.
I have an entry field in my tkinter GUI app. entry should only accept numbers including decimal points. I used a function to validate the entry. The problem is, it is not accepting decimal point(.) if there is a digit in front of it. (example 25.3 wont accept). if there is a point in the beginning, it is not accepting any number after that. Could anyone help me with this problem. and any suggestion to limit the maximum value in the entry field to 1000?
import tkinter as tk
def acceptNumber(inp):
if inp.isdigit():
return True
elif inp is "":
return True
elif inp is ".":
return True
else:
return False
win = tk.Tk()
reg = win.register(acceptNumber)
entryHere =tk.Entry(win)
entryHere.place(x=400, y=200)
entryHere.config(validate="key", validatecommand =(reg, '%P'))
win.mainloop()

This accepts valid decimal numbers not greater than 1000:
def acceptNumber(inp):
try:
return True if inp == '' else float(inp) <= 1000
except:
return False

>>> s='1234'
>>> s.isdigit()
True
>>> sdot = '1234.'
>>> sdot.isdigit()
False
Isn't this your problem. isdigit() means digits only.

Related

I need help on comparing using operators in a guessing game - tkinter [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
So basically, I am making a guessing game in Tkinter. I am comparing numbers to check if the number the user has guessed is greater, lesser, or the same compared to the randomly generated number. I am getting an error about my operator so please provide the correct code, thanks. Here is my code:
from tkinter import messagebox
import random
from tkinter import *
root = Tk()
r = random.randint(1,100)
root.title("Game thing")
def clear():
number_entry1.delete(0,END)
def quit():
exit()
def Guessnumber():
if number_entry1.get() > int(r):
m1 = messagebox.showinfo("Sorry","Lower")
elif number_entry1.get() < int(r):
m2 = messagebox.showinfo("Sorry","Higher")
else:
m3 = messagebox.showinfo("Congratulations","You Got It!")
message_label = Label(root,text = "Guess the number form (1 - 100)")
message_label.grid(row = 0, column = 0)
number_entry1 = Entry(root)
number_entry1.grid(row = 0, column = 1,columnspan = 2)
guess_button = Button(root,text = "Guess Number",fg = "green",command = Guessnumber)
guess_button.grid(row = 1, column = 0, sticky = W)
clear_button = Button(root,text = "Clear",fg = "blue",command = clear)
clear_button.grid(row = 1, column = 1, sticky = W)
quit_button = Button(root,text = "Quit",fg = "red",command = exit)
quit_button.grid(row = 1, column = 2, sticky = E)
Thanks!!! Also if you could I would like an explanation on why I am getting an error.
Again thanks for all the help everyone
The error (which you should have provided in the question but I already detected it) is caused because You compare a string with an integer here:
def Guessnumber():
if number_entry1.get() > int(r):
m1 = messagebox.showinfo("Sorry","Lower")
elif number_entry1.get() < int(r):
m2 = messagebox.showinfo("Sorry","Higher")
else:
m3 = messagebox.showinfo("Congratulations","You Got It!")
Why? because using the .get() method of Entry widgets returns the value of what was entered in the widget as a string, so the simple solution would be this:
def Guessnumber():
if int(number_entry1.get()) > int(r):
m1 = messagebox.showinfo("Sorry","Lower")
elif int(number_entry1.get()) < int(r):
m2 = messagebox.showinfo("Sorry","Higher")
else:
m3 = messagebox.showinfo("Congratulations","You Got It!")
Oh, and also to mention, this is not necessary: int(r), because the function random.randint(1,100) already returns an integer so converting it again is redundant.
And also the function quit() is quite useless since the only thing defined there is the built-in exit() which actually is the same length as in characters so kinda pointless without other functionality
The "final version" of how that function "should" (to the best practices I know) look is this (also includes some PEP 8 - Style Guide for Python Code suggestions and also that there is now only one .get() call which theoretically improves performance since now the method in all cases has to be called only once):
def guess_number():
user_input = int(number_entry1.get())
if user_input > r:
messagebox.showinfo("Sorry", "Lower")
elif user_input < r:
messagebox.showinfo("Sorry", "Higher")
else:
messagebox.showinfo("Congratulations", "You Got It!")

Similar validation functions don't work

First of all, sorry for not using OOP, I just decided to avoid complexity for such a small program.
So here's my program (basically, it's an Entry widget that allows a text that only consists of integers whose maximum length is 5):
from tkinter import *
root = Tk()
root.title("Entry Validation")
root.geometry("300x100")
def validation_function(text):
if len(text) <= 5:
try:
text = int(text)
return True
except:
return False
else:
return False
vcmd = root.register(validation_function)
entry = Entry(root, validate='key', validatecommand=(vcmd, "%P"))
entry.pack()
It works normal. But when I make a little change in the body of the validation function, it doesn't work:
def validation_function(text):
try:
text = int(text)
if len(text) <= 5:
return True
else:
return False
except:
return False
I feel the problem is here:
except:
return False
Probably the max length part doesn't go well with try-except... However:
def validation_function(text):
try:
if len(text) <= 5:
return True
else:
return False
except:
return False
works correctly. But there is only the max length part, I also want it to allow only integers. I've done it in the first example, but my question is: why doesn't it work when I change the places of the max length part with the only integers part?
text is an int ... you cannot call len(int) ... it will raise an exception
try this
def validation_function(text):
try:
int(text)
except:
return False
if len(text) <= 5:
return True
return False

messagebox stops validation

I don't understand why a messagebox (or simpledialog) breaks the flow of the following code. The code basically validates an entry box in python 3.5. It checks that the field only contain numeric values and that it does't go over 9 digits long, the entry box can be empty though. The addition of a message to the user, after they OK it, allows the entry box to be more than 9 digits and accepts letter which of course I don't want it to do.
from tkinter import *
from tkinter import simpledialog
from tkinter import messagebox
root = Tk()
root.title("Zebra")
root.update_idletasks()
root.geometry("350x200+600+300")
root.config(bg="blue")
def okay(old,new): #,c,d,e,f,g,h):
try:
x = int(new)
except ValueError as ex:
if len(new) == 0:
return True
else:
return False
else:
if len(new) > 9:
messagebox.showerror("Error","Entry is too long")
# When messagebox is removed or commented out all is working ok
# but add below line and BINGO it works again :-)
txtNorm.config(validate='all', vcmd=vcmd)
# New line above as of 08/03/2016 brings validation back.
return False
elif len(new) <=9:
return True
finally:
if len(new) > 9:
return False
pass
def txtNormToggle(event): # When the user double clicks the field to enter or correct a number.
txtNorm.config(state="normal")
def txtNormFinished(a):
txtNorm.config(state="disabled")
root.focus()
vcmd=(root.register(okay),'%s','%P')
txtNorm = Entry(root)
txtNorm.grid(row=1, column=1,padx=(15,15),pady=(15,15), sticky=E+W)
txtNorm.insert(0,"123")
txtNorm.config(state="disabled", justify="center", validate='all', vcmd=vcmd)
txtNorm.bind('<Button>',txtNormToggle)
txtNorm.bind('<Control-z>',txtNormFinished)
txtNorm.bind('<Escape>',txtNormFinished)
txtNorm.bind('<Return>',txtNormFinished)
root.mainloop()
The above without the messagebox stops the user entering anything other than digits, which i want, with messagebox once OK is clicked the entry field allows more than 9 digits and other characters
edit: ok so I have created my own pop-up child window and the validation still goes out the window, suspect it is something to do with loss of focus from the main window killing the validation from the entry box. Any ideas please.
i have added validate back to the entry box in the (okay) function, it does't explain to me why the loss of validation occurs though. The code works now how i wanted

Limit user input to numbers? Tkinter-Python [duplicate]

This question already has answers here:
Interactively validating Entry widget content in tkinter
(10 answers)
Closed 8 years ago.
I am trying to make a basic calculator in python tkinter. I made an entry box that user types his first number into. But then, what if someone enters in something other than numbers, but text? My question is, how to make that you can put only number to entry box, or how it can ignore normal letters.
By the way, my half-done code is here:
from tkinter import *
okno = Tk()
okno.title("Kalkulačka")
okno.geometry("400x500")
firstLabel = Label(text="Vaše první číslo").place(x=25, y=25)
firstInput = Entry(text="Vaše první číslo").place(x=130, y=25, width=140)
buttonplus = Button(text="+").place(x=130, y=75)
buttonminus = Button(text="-").place(x=165, y=75)
buttonkrat = Button(text="・").place(x=197, y=75)
buttondeleno = Button(text=":").place(x=237, y=75)
What I would do personally is run every user input through an integer verifying function before accepting it as input. Something simple like this:
def is_int(x):
try:
x = int(x)
return True
except:
return False

raw_input and timeout [duplicate]

This question already has answers here:
Keyboard input with timeout?
(28 answers)
Closed 8 years ago.
I want to do a raw_input('Enter something: .'). I want it to sleep for 3 seconds and if there's no input, then cancel the prompt and run the rest of the code. Then the code loops and implements the raw_input again. I also want it to break if the user inputs something like 'q'.
There's an easy solution that doesn't use threads (at least not explicitly): use select to know when there's something to be read from stdin:
import sys
from select import select
timeout = 10
print "Enter something:",
rlist, _, _ = select([sys.stdin], [], [], timeout)
if rlist:
s = sys.stdin.readline()
print s
else:
print "No input. Moving on..."
Edit[0]: apparently this won't work on Windows, since the underlying implementation of select() requires a socket, and sys.stdin isn't. Thanks for the heads-up, #Fookatchu.
If you're working on Windows you can try the following:
import sys, time, msvcrt
def readInput( caption, default, timeout = 5):
start_time = time.time()
sys.stdout.write('%s(%s):'%(caption, default));
input = ''
while True:
if msvcrt.kbhit():
chr = msvcrt.getche()
if ord(chr) == 13: # enter_key
break
elif ord(chr) >= 32: #space_char
input += chr
if len(input) == 0 and (time.time() - start_time) > timeout:
break
print '' # needed to move to next line
if len(input) > 0:
return input
else:
return default
# and some examples of usage
ans = readInput('Please type a name', 'john')
print 'The name is %s' % ans
ans = readInput('Please enter a number', 10 )
print 'The number is %s' % ans
I have some code which makes a countdown app with a tkinter entry box and button so they can enter something and hit the button, if the timer runs out the tkinter window closes and tells them they ran out of time.
I think most other solutions to this problem don't have a window which pops up so thought id add to the list :)
with raw_input() or input(), it isn't possible as it stops at the input section, until it receives input, then it carries on...
I have taken some code from the following link:
Making a countdown timer with Python and Tkinter?
I used Brian Oakley's answer to this problem and added the entrybox etc.
import tkinter as tk
class ExampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
def well():
whatis = entrybox.get()
if whatis == "": # Here you can check for what the input should be, e.g. letters only etc.
print ("You didn't enter anything...")
else:
print ("AWESOME WORK DUDE")
app.destroy()
global label2
label2 = tk.Button(text = "quick, enter something and click here (the countdown timer is below)", command = well)
label2.pack()
entrybox = tk.Entry()
entrybox.pack()
self.label = tk.Label(self, text="", width=10)
self.label.pack()
self.remaining = 0
self.countdown(10)
def countdown(self, remaining = None):
if remaining is not None:
self.remaining = remaining
if self.remaining <= 0:
app.destroy()
print ("OUT OF TIME")
else:
self.label.configure(text="%d" % self.remaining)
self.remaining = self.remaining - 1
self.after(1000, self.countdown)
if __name__ == "__main__":
app = ExampleApp()
app.mainloop()
I know what I added was a bit lazy but it works and it is an example only
This code works for Windows with Pyscripter 3.3
For rbp's answer:
To account for input equal to a Carriage Return simply add a nested condition:
if rlist:
s = sys.stdin.readline()
print s
if s == '':
s = pycreatordefaultvalue

Categories