messagebox stops validation - python

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

Related

Validation python, Using GUI

I am attempting to validate the text box field so that the user can only insert integers, although i have used a while loop to attempt and cannot figure it out I keep getting errors. Please help.
from tkinter import *
import tkinter as tk
from tkinter.tix import *
# setup the UI
root = Tk()
# Give the UI a title
root.title("Distance converter Miles to Kilometers")
# set window geometry
root.geometry("480x130")
# setup the buttons
valRadio = tk.IntVar()
myText=tk.StringVar()
e1 =tk.IntVar()
def calculate(*arg):
while True:
try:
if valRadio.get() == 1:
# get the miles ( Calculation )
res = round(float(e1.get()) / 1.6093,2)
# set the result text
myText.set( "Your input converts to " + str(res) + " Miles")
break
if valRadio.get() == 2:
# get the kilometeres
res = round(float(e1.get()) * 1.6093,2)
# set the result text
myText.set( "Your input converts to " + str(res) + " Kilometers")
break
if ValueError:
myText.set ("Please check selections, only Integers are allowed")
break
else:
# print error message
res = round(float(e1.get()) / 1.6093,2)
myText.set ("Please check selections, a field cannot be empty")
break
except ValueError:
myText.set ("Please check selections, a field cannot be empty")
break
# Set the label for Instructions and how to use the calculator
instructions = Label(root, text="""Hover me:""")
instructions.grid(row=0, column=1)
# set the label to determine the distance field
conversion = tk.Label( text=" Value to be converted :" )
conversion.grid(row=1,column = 0,)
# set the entry box to enable the user to input their distance
tk.Entry(textvariable = e1).grid(row=1, column=1)
#set the label to determine the result of the program and output the users results below it
tk.Label(text = "Result:").grid(row=5,column = 0)
result = tk.Label(text="(result)", textvariable=myText)
result.grid(row=5,column=1)
# the radio button control for Miles
r1 = tk.Radiobutton(text="Miles",
variable=valRadio, value=1).grid(row=3, column=0)
# the radio button control for Kilometers
r2 = tk.Radiobutton(text="Kilometers",
variable=valRadio, value=2).grid(row=3, column=2)
# enable a calculate button and decide what it will do as well as wher on the grid it belongs
calculate_button = tk.Button(text="Calculate \n (Enter)", command=calculate)
calculate_button.grid(row=6, column=2)
# deploy the UI
root.mainloop()
I have attempted to use the While loop inside the code although I can only get it to where if the user inputs text and doesn't select a radio button the error will display but I would like to have it where the text box in general will not allow anything but integers and if it receives string print the error as it does if the radio buttons aren't selected.
define validation type and validatecommand. validate = key makes with every key input it runs validatecommand. It only types if that function returns true which is 'validate' function in this case.
vcmd = (root.register(validate), '%P')
tk.Entry(textvariable = e1,validate="key", validatecommand=vcmd).grid(row=1, column=1)
this is the validation function
def validate(input):
if not input:
return True
elif re.fullmatch(r'[0-9]*',input):
return True
myText.set("Please check selections, only Integers are allowed")
return False
it return true only when its full of numbers([0-9]* is an regular expression which defines all numbers) or empty. If it contains any letter it return False any it denied this way.
Also do not forget to imports
import re

Tkinter/Python hanging on user response if response is the last option in a while or if loop

The following code works for requesting input from a user through the Tkinter GUI and turning that input into a usable variable in the main script. However, any value that I put as the last in a list in the if statement (here "4") will hang and crash the program upon enter. This was also the case for "n" in a yes/no scenario. It also happens if I replace the if statement with a while not in [values] - the final value will crash the program. Is this just a quirk of Tkinter or is there something that I am missing?
import tkinter as tk
from tkinter import *
# get choice back from user
global result
badinput = True
while badinput == True:
boxwidth = 1
result = getinput(boxwidth).strip().lower()
if result in ['1', '2', '3', '4']:
badinput = False
# iterate through play options
if result == '1':
# Do Something
elif result =='2':
# Do Something
elif result =='3':
# Do Something
else:
# Do Something
def getinput(boxwidth):
# declaring string variable for storing user input
answer_var = tk.StringVar()
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
return
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(answer_var)
answer_entry.destroy()
return answer_var.get()
In case anyone is following this question, I did end up solving my problem with a simple if statement within the callback. I can feed a dynamic "choicelist" of acceptable responses into the callback upon user return. If the answer is validated, the gate_var triggers the wait function and sends the program and user response back into the program.
'''
def getinput(boxwidth, choicelist):
# declaring string variable for storing user input
answer_var = tk.StringVar()
gate_var = tk.StringVar()
dumplist = []
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
if choicelist == None:
clearscreen(dumplist)
gate_var.set(answer_entry.get())
return
if answer_var.get() in choicelist:
# passes a validated entry on to gate variable
clearscreen(dumplist)
gate_var.set(answer_entry.get())
else:
# return to entry function and waits if invalid entry
clearscreen(dumplist)
ErrorLabel = tk.Label(root, text = "That is not a valid response.")
ErrorLabel.pack()
ErrorLabel.config(font = ('verdana', 18), bg ='#BE9CCA')
dumplist.append(ErrorLabel)
return
global topentry
if topentry == True:
answer_entry = tk.Entry(top, width = boxwidth, borderwidth = 5)
else:
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(gate_var)
answer_entry.destroy()
return answer_var.get()
'''

validation of tkinter entry widget [duplicate]

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.

Increment everytime i press + button

I'm working on this Incrementor Decrementor program .. where First i enter a number and as i press + the entered number is incremented by 1 and decrements when i press - ... The problem is the value is getting incremented or decremented only once.
from tkinter import *
#******* Functions code ********
def add(event):
a=float(enter.get())
b=a+1
labelresult=Label(root,text="Result : %2f"%b).grid(row=3,column=1)
return
def sub(event):
a=float(enter.get())
b=a-1
labelresult=Label(root,text="Result : %2f"%b).grid(row=3,column=1)
return
#******* GUI code***********
root=Tk()
root.geometry('250x250')
root.title('Incrementor or Decrementor')
enter=IntVar()
label=Label(root,text="Skz.inc",bg='skyblue',fg='red').grid(row=0,column=1)
label=Label(root,text="enter a number").grid(row=1)
entry_1=Entry(root,textvariable=enter).grid(row=1,column=1)
button1=Button(root,text='+')
button1.grid(row=2,column=0)
button1.bind('<Button-1>',add)
button2=Button(root,text='-')
button2.grid(row=2,column=3)
button2.bind('<Button-1>',sub)
root.mainloop()
So the value which i entered should be increment or decrement each time i press either + or - button .
Example - when i enter 9 and press + the result should be 10 (works in my program) . Again on pressing + button the result should be 11 which is not the case in my code.
Help me out guys .. do modify and send me back the code.
Thanks
Each time you press + or - the function reads the value in the entry. You will have to update the value in the entry for every add or sub.
def add(event):
a=float(enter.get())
b=a+1
labelresult.config(text="Result : %2f"%b) # Update labelresult instead of
# creating a new label every time
enter.set(b) # Set entry to the new value
return
You will have to create labelresult in the GUI code:
labelresult = Label(root)
labelresult.grid(row=3,column=1)

Why does it return the none in python shell

I am trying to create a program which only allows you to write a certain amount of characters as a prompt while using a text box. When I try to run the program it returns none in the python shell and doesn't complete the function I would like it to. I would like it to write "your prompt has been posted" if there are under ten characters and write "The prompt is too long" if there are over 10 character. Thanks in advance for the help. It is greatly appreciated
label = Label(tk, text="Prompt:")
label.place(relx=0.1, rely=0.2, anchor=CENTER)
text = Text(tk, width=50, height=6, bg="gray")
text.place(relx=0.62, rely=0.2, anchor=CENTER)
def diary():
print("Why does this not work")
def begin():
while True:
answer = input(text.insert(INSERT, diary))
if len(answer) <= 10:
print("Your prompt has been posted")
else:
print("The prompt is too long")
button = Button(tk, text="Submit", command=begin)
button.place(relx=0.5, rely=0.5, anchor=CENTER)
The code never ends because you told it to run a loop forever without changing anything that would cause it to stop.
Also, whatever you think this code is doing, it's probably not doing it. I count at least three things wrong with this one line of code:
answer = input(text.insert(INSERT, diary))
The input command will read in put from the command line (technically, stdin), which is not something you typically do in a GUI. You are passing it the result of a call to text.insert, but text.insert isn't documented to return anything. Plus, you're giving text.insert a function where it expects a string.
If you want to insert what the function diary returns, you must a) define diary to do something, and b) call it as a function. For example:
def diary():
return "something"
...
text.insert(INSERT, diary())
If your real goal is to have begin get what the user has entered in the GUI and check the length, then you need to remove the while loop and replace the call to insert with get:
def begin():
answer = text.get("1.0", "end-1c")
if len(answer) <= 10:
print("Your prompt has been posted")
else:
print("The prompt is too long")

Categories