Restricting the Value in Tkinter Entry Widget

Restricting user entry in Entry field in Tkinter without 'disabled' method

One of the way is to create a custom class inherited from Entry and override the insert():

import tkinter as tk
...

class MyEntry(tk.Entry):
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
# make it disabled, but with black on white like in normal state
self.config(state='disabled', disabledforeground='black', disabledbackground='white')

def insert(self, pos, value):
self.config(state='normal')
super().insert(pos, value)
self.config(state='disabled')

def delete(self, first, last=None):
self.config(state='normal')
super().delete(first, last)
self.config(state='disabled')

...

field = MyEntry(...) # use MyEntry instead of tk.Entry
...

It still uses 'disabled' state, but you don't need to change the other parts of your application.

How to restrict Text widget input to certain characters with Tkinter?

Returning "break" from a function that is called from an event, will stop the event. That means that tkinter's widget will never get the event.

How to restrict the maximum number a user can enter in an entry widget?

In this case , try using SpinBox Instead of Entry Widget .

For example :

from tkinter import *  

top = Tk()

top.geometry("200x200")

spin = Spinbox(top, from_= 0, to = 25)

spin.pack()

top.mainloop()

To get the SpinBox current value , you can just simply do : spin.get()

Tkinter: restrict entry data to float

The right tool is definitely the re module.

Here is a regular expression that should do the job:

(\+|\-)?\d+(,\d+)?$

Let's break it down:

(\+|\-)?\d+(,\d+)?$

\+|\- Starts with a + or a -...
( )? ... but not necessarily
\d+ Contains a repetition of at least one digits
,\d+ Is followed by a comma and at least one digits...
( )? ... but not necessarily
$ Stops here: nothing follows the trailing digits

Now, your validate function only has to return True if the input matches that regex, and False if it does not.

def validate(string):
result = re.match(r"(\+|\-)?\d+(,\d+)?$", string)
return result is not None

Some tests:

# Valid inputs
>>> validate("123")
True
>>> validate("123,2")
True
>>> validate("+123,2")
True
>>> validate("-123,2")
True

# Invalid inputs
>>> validate("123,")
False
>>> validate("123,2,")
False
>>> validate("+123,2,")
False
>>> validate("hello")
False


Edit

I understand now that you want to check in real-time if the input is valid.
So here is an example of what you can do:

import tkinter as tk
import re

def validate(string):
regex = re.compile(r"(\+|\-)?[0-9,]*$")
result = regex.match(string)
return (string == ""
or (string.count('+') <= 1
and string.count('-') <= 1
and string.count(',') <= 1
and result is not None
and result.group(0) != ""))

def on_validate(P):
return validate(P)

root = tk.Tk()
entry = tk.Entry(root, validate="key")
vcmd = (entry.register(on_validate), '%P')
entry.config(validatecommand=vcmd)
entry.pack()
root.mainloop()

The validate function now checks more or less the same thing, but more loosely.
Then if the regex results in a match, some additional checks are performed:

  • Allow the input to be empty;
  • Prevent the input to have more than one '+'/'-', and more than one ',';
  • Ignore a match against the empty string, because the pattern allows it, so "a" would result in a match but we don't want it.

The command is registered, and works with the '%P' parameter, that corresponds to the string if the input were accepted.

Please not however that forcing the input to be always correct is somewhat harsh, and might be counter-intuitive.
A more commonly used approach is to update a string next to the entry, and have the user know when their input is valid or invalid.



Related Topics



Leave a reply



Submit