I am trying to interactively validate an entry widget in tkinter to only allow the user to enter characters in the alphabet.
I have already read a very popular thread (Interactively validating Entry widget content in tkinter) and from that I have tried to figure out my solution but I just cannot seem to get it working.
In the comments of that thread was a solution that only allowed numbers, I have used that for one area of my program and it works perfectly! Code here:
from tkinter import *
root = Tk()
def testVal(inStr,i,acttyp):
ind=int(i)
if acttyp == '1': #insert
if not inStr[ind].isdigit():
return False
return True
entry = Entry(root, validate="key")
entry['validatecommand'] = (entry.register(testVal),'%P','%i','%d')
entry.pack()
root.mainloop()
I would like a solution like this, with the only change being that it accepts letters instead of numbers. Any help appreciated
Here's the solution you're looking for:
def testVal(inStr,i,acttyp):
ind=int(i)
if acttyp == '1': #insert
if not inStr[ind].isalpha():
return False
return True
Heres some other things which might be useful:
.isdigit() tests if a string is an integer
.isalpha() tests if a string contains only letters
.isalnum() tests if a string contains only letters and numbers
.isupper() tests for uppercase
.islower() tests for lowercase
For other datatypes you can use isinstance(), for example isinstance("34.5", float) will return True
Source: https://docs.python.org/3/library/stdtypes.html
Related
I want to create a simple game in Python 3.8, and i need to verify an entry`s input in order to create it. Something like this:
if input.text == "":
print("Error")
but i don`t know how to do this in Python. I used to do that a lot in C# but here it s not that easy apparently.
Considering you are talking about an Entry and also have the Tag tkinter in your question I assume you want to get some user input from a tkinter Entry widget.
To get a value from a Entry widget you can use the get() method. This returns a string.
You can use a simple button command or a bind() to call a function that then checks the value of the entry field.
You can also throw in a strip() just in case the user uses a space or two without imputing anything else. This way a string of spaces still returns back as an error.
Here is a simple example:
import tkinter as tk
def check_entry():
value = entry.get().strip()
if value == '':
print('Error')
else:
print('Value is not an empty string. Now do something.')
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
tk.Button(root, text='Check Entry', command=check_entry).pack()
root.mainloop()
To get an input, you can use the input function. This will automatically return a string. Here is sample usage of this:
user_input = input("Please put your input here: ") # Get user input
if user_input == "": # Compare input to empty string
print("Error")
You can see the Python docs for more information about input.
Try with:
# get the input using the input built-in function
user_input = input("insert your input here: ")
# check the input
if user_input == "":
# raise an exception and stop the program
raise ValueError("invalid input! Empty string")
I have written a script simulating a card game in Python where the user decides how many cards and how many piles of cards they want to play with. This input is controlled by following code where boundary_1 and boundary_2 give upper and lower limit in an integer interval and message is the user input:
def input_check(boundary_1, message, boundary_2):
run = True
while run:
try:
user_input =int(input(message))
if boundary_1 <= user_input <= boundary_2:
run = False
return user_input
else:
print ("Incorrect Value, try again!")
run = True
except ValueError:
print ("Incorrect Value, try again!")
I now want to try and make a GUI out of this card game using tkinter and I would therefore like to know if there's any way to save the user's input to a variable that could be sent into the input_check() function above? I've read through some tutorials on tkinter and found the following code:
def printtext():
global e
string = e.get()
text.insert(INSERT, string)
from tkinter import *
root = Tk()
root.title('Name')
text = Text(root)
e = Entry(root)
e.pack()
e.focus_set()
b = Button(root,text='okay',command=printtext)
text.pack()
b.pack(side='bottom')
root.mainloop()
The following code simply prints the user's input in the Textbox, what I need is the user's input being checked by my input_check() and then have an error message printed in the Textbox or the input saved to a variable for further use if it was approved. Is there any nice way to do this?
Many thanks in advance!
The simplest solution is to make string global:
def printtext():
global e
global string
string = e.get()
text.insert(INSERT, string)
When you do that, other parts of your code can now access the value in string.
This isn't the best solution, because excessive use of global variables makes a program hard to understand. The best solution is to take an object-oriented approach where you have an "application" object, and one of the attributes of that object would be something like "self.current_string".
For an example of how I recommend you structure your program, see https://stackoverflow.com/a/17470842/7432
I have seen several questions on tkinter entry validation here but each one seems to stick to validate="key" option.
While this is great for interactive validation, what i want is a "focusout" validation.
More particularly I am looking to validate an email field. Here's the code I have tried so far but it doesn't work.
import Tkinter as tk
import re
master = tk.Tk()
def validateEmail(P):
x = re.match(r"[^#]+#[^#]+\.[^#]+", P)
return (x != None)
vcmd = (master.register(validateEmail), '%P')
emailentry = tk.Entry(master, validate="focusout", validatecommand=vcmd)
emailentry.pack()
b = tk.Button(master, text="Login")
b.pack()
tk.mainloop()
Any ideas on how to validate email entry please ?
%S represents the string being inserted, if any. This is only meaningful for validation on text insertion. When the widget loses focus, no character is being inserted so this parameter will always be an empty string. Since it is an empty string, it will always fail your validation.
You should use %P instead, which represents the whole string.
Also, strictly speaking, the validation function should return a boolean rather than an object. You should save the result of the match in a variable, then return something like return (match is not None)
Question
Why is my random ascii character selector function outputting fours, and what is the significance of the number four in this context? Why am I not recieving an error message?
Remember, the question is not about how to solve the issue, it is about why that particular number was output.
Background and Code
I am trying to creating a basic email client. I thought that it would be cool for my password box to show random characters instead of the obvious *. So, I created a function which chose a random ascii letter.
import random
import string
def random_char():
char_select = random.randrange(52)
char_choice = string.ascii_letters[char_select]
return char_choice
When I run this in an interactive terminal, it spits out a random letter. But, when I run it through my widget
self.Password = Entry (self, show = lambda: random_char())
I am met with a bunch of fours.
Extra Credit
If you have the time, please visit my related question, How to have a Tkinter Entry box repeat a function each time a character is inputted?
The show parameter accepts a value not a callback. Tkinter is taking your callback object and trying to convert it to a string and that is what you get when you type in the Entry box.
Instead you can re-configure your Entry after you type by using binding:
def key(event):
entry.configure(show = random_char())
entry = tk.Entry (self)
entry.pack()
entry.bind("<Key>", key)
EDIT
Bryan Oakley is correct in that this will change all the characters to the same single random character as you type. Showing different random characters as you type is not the way you are supposed to use the Entry widget. You can try something like:
def key(event):
global real_password
global garbage
current_len = len(v.get())
if event.char and event.char in string.ascii_letters:
real_password += event.char
garbage += random_char()
garbage = garbage[:current_len]
v.set(garbage)
v = tk.StringVar()
real_password = ""
garbage = ""
entry = tk.Entry (self, textvariable = v)
entry.pack()
entry.bind("<KeyRelease>", key)
Of course there are lots of limitations, the last character typed is changed when the key is released not when is pressed, so you have to type fast :) , there is not control over the cursor movement keys etc. But anyway it was fun trying.
I've got a problem with Entry widget while making a copy of Windows Calc.
I have made buttons like in windows calc and I also bind the keyboard 1234567890 + - / * % buttons, to make the same things as the calc buttons.
The mainly problem was that I wanted the Entry to store only numbers and let user input only numbers... but after searching many topics about validatecommand and also looking at windows calc I decided that validatecommand isn't the thing I need - I don't know how to make it validate every character the user inputs to the entry box and after making the keyboard binds, when I am in entrybox and press "1" to write the number it does it two times, because the keyboard event binding inserts the "1" to the entry box too.
So, the thing I want to make is to make entry widget work like the Windows Calc.exe entry box.
The windows calc entry box doesn't let you insert any other character then numbers and also doesn't let you to put your cursor into the entry box...,
it looks like this:
-entrybox is disabled BUT it looks like ENABLED
-numbers and operations can be made by calc buttons or by keyboard buttons
I tried getting this effect by disabling the entry widget at start, and making all buttons functions like that:
-enable the entry widget
-insert the number (the widget must be in enabled? or normal? (don't remember the name) state to let you insert something to it)
-disable the entry widget
It works like I want... but it doesn't look like I want it to look. Is there any possibility to change Entry widget disabled bg color to normal?
Or maybe is there another way to make such entry box? :S
The way to do it is with the validatecommand and validate options of the entry widget. This scenario is precisely what those features are for.
You say you "don't know how to make it validate every character the user inputs to the entry box". If you set the validate attribute to "key", that will cause your validate command to be called on every keypress.
Unfortunately, this is a somewhat under-documented feature of Tkinter, though it's documented quite well for Tk. Here's a working example which performs some very rudimentary checks:
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
# define a command to be called by the validation code. %P
# represents the value of the entry widget if the edit is
# allowed. We want that passed in to our validation comman so
# we can validate it. For more information see
# http://tcl.tk/man/tcl8.5/TkCmd/entry.htm#M7
vcmd = (self.register(self._validate), '%P')
e = tk.Entry(self, validate="key", validatecommand=vcmd)
e.pack()
def _validate(self, P):
# accept the empty string, "." or "-." (to make it possible to
# enter something like "-.1"), or any string that can be
# converted to a floating point number.
try:
if P in (".", "-", "-.", ""):
return True
n = float(P)
return True
except:
self.bell()
return False
app=SampleApp()
app.mainloop()
If you search this site for [tkinter] validatecommand you'll find many other examples.