validating a text entry on tkinter - python

I'm creating a program that allows the user to select a category and enter a value to calculate a charge. I would like to validate the text entry using my own validation file. However, when I run the program and enter nothing in the text entry, the error window keeps popping up over and over again. In addition, when I run the program and enter a valid number in the entry field, the charge comes out to 0.0, even though I have defined the calculation for the total charge.
Here is the program:
import tkinter
import tkinter.messagebox
import ValidationFile
validationObject = ValidationFile.ValidationClass ()
class MyGUI:
def __init__ (self):
self.main_window = tkinter.Tk ()
self.top_frame = tkinter.Frame (self.main_window)
self.middle_frame = tkinter.Frame (self.main_window)
self.bottom_frame = tkinter.Frame (self.main_window)
self.phone_var = tkinter.IntVar ()
self.phone_var.set (1)
self.pb1 = tkinter.Radiobutton (self.top_frame, \
text = 'Daytime (6:00 AM - 5:59 PM)', variable = self.phone_var, \
value = 0.12)
self.pb2 = tkinter.Radiobutton (self.top_frame, \
text = 'Evening (6:00 PM - 11:59 PM)', variable = self.phone_var, \
value = 0.07)
self.pb3 = tkinter.Radiobutton (self.top_frame, \
text = 'Off-Peak (Midnight - 5:50 AM)', variable = self.phone_var, \
value = 0.05)
#pack phone buttons
self.pb1.pack ()
self.pb2.pack ()
self.pb3.pack ()
#create input and output buttons
self.txtInput = tkinter.Entry (self.middle_frame, \
width = 10)
self.value = tkinter.StringVar ()
self.lblOutput = tkinter.Label (self.middle_frame, \
width = 10, textvariable = self.value)
self.txtInput.pack()
self.lblOutput.pack ()
#create OK buton and QUIT button
self.ok_button = tkinter.Button (self.bottom_frame, \
text = 'OK', command = self.show_choice)
self.quit_button = tkinter.Button (self.bottom_frame, \
text = 'QUIT', command = self.main_window.destroy)
#pack the buttons
self.ok_button.pack (side = 'left')
self.quit_button.pack (side = 'left')
#pack the frames
self.top_frame.pack ()
self.middle_frame.pack ()
self.bottom_frame.pack ()
#start the mainloop
tkinter.mainloop ()
def show_choice (self):
choice = self.phone_var.get ()
value = -1
while value == -1:
valueEntry = self.txtInput.get()
if valueEntry == '':
value = -1
tkinter.messagebox.showinfo (title = 'ERROR', \
message = 'Please enter a valid number.')
else:
value = validationObject.checkFloat (valueEntry)
total = choice * value
self.value.set (total)
#create instance of MyGUI class
my_GUI = MyGUI ()
Here is the validation file:
#create validation class
class ValidationClass:
def checkFloat (self, inputString):
try:
result = float (inputString)
except Exception:
return -1
if result < 0:
return -1
else:
return result
def checkInteger (self, inputString):
try:
result = int (inputString)
except Exception:
return -1
if result < 0:
return -1
else:
return result

You made an infinite loop with while value == -1:. Nowhere in that loop do you pause to allow the user to try again. You don't need the loop at all:
def show_choice (self):
valueEntry = self.txtInput.get()
value = validationObject.checkFloat(valueEntry)
if value == -1:
tkinter.messagebox.showinfo (title = 'ERROR', \
message = 'Please enter a valid number.')
else:
choice = self.phone_var.get()
total = choice * value
self.value.set (total)
Once you fix that you will have another problem: you use float values in your options but the variable is an IntVar, which can only handle integers. So "choice" will always be 0. You need to use DoubleVar instead.

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

Connect a python script with Tkinter

I want to design a Gui script for a NameSort script.
I want to develop a python3 script with Gui. Here is my code for Cli only
text = open('/Users/test/Desktop/readme.txt','r')
def readtxt(txt): #turns txt to ls
dictls=(txt.read()).splitlines()
return dictls
def getdict(dictls): #turns to dictionary
dict1 = {dictls.index(i) : i for i in dictls}
return dict1
def getkey(diction,index): #getkey
return diction[index]
def randomord(x,z): #random order generator, won't generate repeditive numbers
import random
output = []
done = []
y = 0 #already generated
while y <= x:
rnum = random.randint(0,z)
if rnum not in done:
output.append(rnum)
done.append(rnum)
y+=1
return output
def main():
ls=readtxt(text)
while True:
print(f'\nThere are {len(ls)} names on the list.')
try:
h = int(input('Number of names to gen: '))
if h-1 <= len(ls)-1:
outls = [getkey(getdict(ls),i) for i in randomord(h-1,len(ls)-1)]
print('\n'.join(outls))
else:
print(f'[*]ERR: There are only {len(ls)} names on the list.')
except:
print('[*]ERR')
main()
Now I have tried these code
text = open('/root/Desktop/Python/gui/hell.txt','r')
def readtxt(txt): #turns txt to ls
dictls=(txt.read()).splitlines()
return dictls
def getdict(dictls): #turns to dictionary
dict1 = {dictls.index(i) : i for i in dictls}
return dict1
def getkey(diction,index): #getkey
return diction[index]
def randomord(x,z): #random order generator, won't generate repeditive numbers
import random
output = []
done = []
y = 0 #already generated
while y <= x:
rnum = random.randint(0,z)
if rnum not in done:
output.append(rnum)
done.append(rnum)
y+=1
return output
def main():
ls=readtxt(text)
while True:
print(f'\nThere are {len(ls)} names on the list.')
try:
h = int(input('Number of names to gen: '))
if h-1 <= len(ls)-1:
outls = [getkey(getdict(ls),i) for i in randomord(h-1,len(ls)-1)]
print('\n'.join(outls))
else:
print(f'[*]ERR: There are only {len(ls)} names on the list.')
except:
print('[*]ERR')
global startmain
startmain = 0
def test1():
startmain = 1
###########################
##########################
###################################
from tkinter import *
import tkinter as tk
window = tk.Tk()
p1 = tk.Label(
text="Thomas-name-sort",
fg="red",
bg='green',
width=10,
height=8
)
name_ent = tk.Label(text="输入生成数量Number of names to gen:")
entry = tk.Entry()
name_ent.pack()
entry.pack()
name = entry.get()
b1 = tk.Button(
text="auto-testing自检",
bg="blue",
fg="orange",
width=20,
height=5,
command=test1()
)
b1.pack()
if startmain == 1:
main()
#bind-zone
window.mainloop()
It does not work.
I want to design a Gui script for a NameSort script.
I could not bind the button with the function
T have tried "command=main()" and "button.bind("", func=main()"
Please help me!!!
To set a button's function in tkinter, you only pass the function itself in the command parameter i.e.
command = test1,
Not command = test1() as in this case you are just giving it the result of the function (which is None). This is so that it can execute the function each time the button is pressed.
If you want to provide in arguments for it to execute, you'll then have to use a lambda function:
command = lambda: test1(param1, param2),
You can find decent guides on buttons in tkinter here if you're interested

Calling Functions within Classes from Tkinter Buttons

I am currently trying to use classes within my code which I have not used before. My goal is to When the power on button is pressed the system the system checks whether the power is on or not and if it is no it returns "Power On" and the same for Power Off and so on. I am currently struggling when the button is pressed I am unsure how to send a command to the function within control with the specified text e.g "PWR"
Below is my code any help is much appreciated thank you
import tkinter as tk
window = tk.Tk()
class Power:
def __init__(self, x):
if x == 0:
# Run def control
# Change function in def control to Power
print ("Power On")
if x == 1:
# Run def control
# Change function in def control to Power
print("Power Off")
if x == 2:
# Run def Control
# Change Function to Inp
# Add which input has been selected to the end of the return
print ("Input 1")
if x == 3:
# Run def Control
# Change Function to Inp
# Add which input has been selected to the end of the return
print ("Input 2")
def control(self, function):
if function[:3] == "PWR":
if "on" in function.lower():
return ("Power On")
elif "off" in function.lower():
return("Power Off")
else:
return ("Power Error")
elif function[:3] == 'INP':
inp = function[3:]
return 'Input ' + inp
CtrlBtnsTxt = ["Power On", "Power Off", "Input 1", "Input 2"]
for i in range (4):
CtrlBtns = tk.Button(window, width = 10, height = 5, text = CtrlBtnsTxt[i], command = lambda x = i: Power (x) )
CtrlBtns.grid (row = i, column = 0)
window.mainloop()
It will be better for the class instance to persist across commands. This way you could simply memorize the current button states and use that to adjust the behavior during the next call :
import tkinter as tk
window = tk.Tk()
class Power:
# ====> Memorizes states
power = False
curInput = 0
# ====> Replace __init__ by a method you can call without creating a new instance
def command(self, x):
if x == 0:
print (self.control("PWR on"))
if x == 1:
print (self.control("PWR off"))
if x == 2:
print (self.control("INP 1"))
if x == 3:
print (self.control("INP 2"))
def control(self, function):
if function[:3] == "PWR":
# ====> Includes the stored state in the tests and stores the new state
if "on" in function.lower() and self.power == False:
self.power = True
return "Power On"
# ====> Idem
elif "off" in function.lower() and self.power == True
self.power = False
return "Power Off"
else:
return ("Power Error")
elif function[:3] == 'INP':
inp = function[3:]
# ====> Optionally you can do the same for the input
if (inp == self.curInput): return 'Input already set'
self.curInput = inp
return 'Input ' + inp
CtrlBtnsTxt = ["Power On", "Power Off", "Input 1", "Input 2"]
# ====> Creates a unique instance of the class and uses it below
power = Power()
for i in range (4):
CtrlBtns = tk.Button(window, width = 10, height = 5, text = CtrlBtnsTxt[i], command = lambda x = i: power.command(x) )
CtrlBtns.grid (row = i, column = 0)
window.mainloop()

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()
'''

How do I make my variable have a default value "0" when no input has been provided by the user in python?

Here is my code. I want my variable "a" to hold a default value 0 whenever the user has not given any particular value. I have given my code below:
from tkinter import *
from tkinter import messagebox
def sample():
a= show_values1()
v= int(a)+10
print (v)
def show_values1(event=None):
global a
a= i1.get()
print(a)
if int(a) > ul or int(a) < ll :
print('Limit Exceed')
messagebox.showerror("Error", "Please enter values from -100 to 100")
else :
return a
root= Tk()
ul= 100
ll=-100
i1 = inputBox = Entry()
i1.place(x=70, y=48, height=20)
bu1=Button(text='Enter', command = show_values1)
bu1.place(x = 70, y = 28, width=40, height=20)
bu2=Button(text='SEND', command = sample)
bu2.bind('<Return>', lambda x: show_values1(event=None))
bu2.place(x = 70, y = 98, width=40, height=20)
root.mainloop()
If no value has been entered, i1.get() will have a value of empty string "", so you could just test for that inside showvalues1:
if a == "":
return 0
As li.get() returns a string. Nothing entered will be a string of zero length. You can test for that and then set a to zero. For axample, after your a = i1.get() statement, insert:
if len(a) == 0:
a = "0"
Maybe you also need to handle cases where get() returns values that are not able to be cast to type int. :-)

Categories