Posts: 11
Threads: 5
Joined: Nov 2019
I'm trying to get this data validation to work. It seems to work ok when checking, but it just does some funny things, that I don't understand. First, here is the code:
import tkinter as tk
from tkinter import messagebox
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
l_focus = self.register(self.leave_field)
self.entry1 = tk.Entry(self)
self.entry2 = tk.Entry(self)
self.entry3 = tk.Entry(self)
self.entry1.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry2.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry3.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry1.pack(side="top", fill="x")
self.entry2.pack(side="top", fill="x")
self.entry3.pack(side="top", fill="x")
def leave_field(self, inp):
if inp == "":
messagebox.showinfo("Blank Entry", "You must enter a number.")
return False
else:
# Check entry is Number
try:
float(inp)
if int(inp) < 10 or int(inp) > 15:
messagebox.showinfo("Out of Range", inp + " is not between 10-15")
return False
else:
return True
except ValueError:
messagebox.showinfo("Not Numeric", inp + " is not a valid number.")
return False So first off, if the first textbox is erroneous, my messagebox pops up, I click ok, and then I have to click back on the textbox to fix the error. Well, this triggers the next textbox's validation check, and it shows empty. Is there a way that I can when I click OK on the message box, the erroneous entry retains focus?
Then, how can I reset the validation check? the %P seems to retain the values, and it triggers the checks more than once. Not sure if I'm explaining this well, but for some reason I tend to get my messageboxes popping up more than once.
Thanks.
Posts: 12,030
Threads: 485
Joined: Sep 2016
Code is not complete. Please supply working snippet
Posts: 11
Threads: 5
Joined: Nov 2019
(Nov-17-2019, 02:21 AM)Larz60+ Wrote: Code is not complete. Please supply working snippet
My apologies. I forgot the bottom portion of the code. Here it is.
import tkinter as tk
from tkinter import messagebox
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
l_focus = self.register(self.leave_field)
self.entry1 = tk.Entry(self)
self.entry2 = tk.Entry(self)
self.entry3 = tk.Entry(self)
self.entry1.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry2.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry3.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry1.pack(side="top", fill="x")
self.entry2.pack(side="top", fill="x")
self.entry3.pack(side="top", fill="x")
def leave_field(self, inp):
if inp == "":
messagebox.showinfo("Blank Entry", "You must enter a number.")
return False
else:
# Check entry is Number
try:
float(inp)
if int(inp) < 10 or int(inp) > 15:
messagebox.showinfo("Out of Range", inp + " is not between 10-15")
return False
else:
return True
except ValueError:
messagebox.showinfo("Not Numeric", inp + " is not a valid number.")
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Posts: 12,030
Threads: 485
Joined: Sep 2016
You were returning False, then ignoring it
also, why conversion to float?
logic is strange
import tkinter as tk
from tkinter import messagebox
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
l_focus = self.register(self.leave_field)
if l_focus:
self.entry1 = tk.Entry(self)
self.entry2 = tk.Entry(self)
self.entry3 = tk.Entry(self)
self.entry1.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry2.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry3.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry1.pack(side="top", fill="x")
self.entry2.pack(side="top", fill="x")
self.entry3.pack(side="top", fill="x")
def leave_field(self, inp):
if inp == "":
messagebox.showinfo("Blank Entry", "You must enter a number between 10 and 15.")
return False
else:
# Check entry is Number
try:
float(inp)
if int(inp) < 10 or int(inp) > 15:
messagebox.showinfo("Out of Range", inp + " is not between 10-15")
return False
else:
return True
except ValueError:
messagebox.showinfo("Not Numeric", inp + " is not a valid number.")
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Posts: 11
Threads: 5
Joined: Nov 2019
Nov-17-2019, 04:24 PM
(This post was last modified: Nov-17-2019, 05:09 PM by p_hobbs.)
(Nov-17-2019, 04:00 PM)Larz60+ Wrote: You were returning False, then ignoring it
also, why conversion to float?
logic is strange
import tkinter as tk
from tkinter import messagebox
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
l_focus = self.register(self.leave_field)
if l_focus:
self.entry1 = tk.Entry(self)
self.entry2 = tk.Entry(self)
self.entry3 = tk.Entry(self)
self.entry1.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry2.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry3.configure(validate="focusout", validatecommand=(l_focus, '%P'))
self.entry1.pack(side="top", fill="x")
self.entry2.pack(side="top", fill="x")
self.entry3.pack(side="top", fill="x")
def leave_field(self, inp):
if inp == "":
messagebox.showinfo("Blank Entry", "You must enter a number between 10 and 15.")
return False
else:
# Check entry is Number
try:
float(inp)
if int(inp) < 10 or int(inp) > 15:
messagebox.showinfo("Out of Range", inp + " is not between 10-15")
return False
else:
return True
except ValueError:
messagebox.showinfo("Not Numeric", inp + " is not a valid number.")
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Well, quite honestly as an explanation, I'm very new to Python, and trying to piece together things I've found on the web that I can apply to my application. So, with that said:
- What do you mean I'm returning false and then ignoring it? Is there a step I'm missing? I'm basically wanting to check the entry, and if it doesn't meet the criteria then show the appropriate message box to alert the user. And actually, thinking about it now (without testing yet), I don't really need it to return true or false, right? Because if the input meets certain criteria set up with "if" statements I just display the messagebox. Correct?
- The conversion to float was my logic telling me how to make sure the input was a numerical value that could have a decimal. But again, thinking about it, could I just change this:
self.entry1.configure(validate="focusout", validatecommand=(l_focus, '%P')) to:
self.entry1.configure(validate="focusout", validatecommand=(l_focus, float('%P'))) and achieve the same result and be able to eliminate part of the checks in my function?
Would it be better to do a Binding to "FocusOut" for the widget, rather than use validatecommand? I wrote this, and it seems to work fine, but my issue now is how to remember the widget that is being checked. In this code I'm only checking Entry1. How would I pass as a variable the widget that is losing focus and triggering the function?
import tkinter as tk
from tkinter import messagebox
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.entry1 = tk.Entry(self)
self.entry2 = tk.Entry(self)
self.entry3 = tk.Entry(self)
self.entry1.bind('<FocusOut>', self.focus_out)
self.entry2.bind('<FocusOut>', self.focus_out)
self.entry3.bind('<FocusOut>', self.focus_out)
self.entry1.pack(side="top", fill="x")
self.entry2.pack(side="top", fill="x")
self.entry3.pack(side="top", fill="x")
def focus_out(self, event):
x = self.entry1.get()
if x == "":
messagebox.showinfo("Blank Entry", "You must enter a number.")
self.entry1.focus_set()
else:
try:
float(x)
if float(x) < 10.0 or float(x) > 15.0:
messagebox.showinfo("Out of Range", x + " is not between 10-15")
self.entry1.focus_set()
except ValueError:
messagebox.showinfo("Not Numeric", x + " is not a valid number.")
self.entry1.focus_set()
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Posts: 11
Threads: 5
Joined: Nov 2019
This is what I came up with. It operates exactly how I want it to. It's probably not the most efficient way of doing what I'm trying to do, but it works. I'd love some more input from people about how I might better achieve this, but as of right now, I'm going to mark the thread as "Solved".
import tkinter as tk
from tkinter import messagebox
class Example_1(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.next_box = True
self.entry1 = tk.Entry(self)
self.entry2 = tk.Entry(self)
self.entry3 = tk.Entry(self)
self.entry1.bind('<FocusIn>', self.focus_in)
self.entry2.bind('<FocusIn>', self.focus_in)
self.entry3.bind('<FocusIn>', self.focus_in)
self.entry1.bind('<FocusOut>', self.focus_out)
self.entry2.bind('<FocusOut>', self.focus_out)
self.entry3.bind('<FocusOut>', self.focus_out)
self.entry1.pack(side="top", fill="x")
self.entry2.pack(side="top", fill="x")
self.entry3.pack(side="top", fill="x")
def focus_out(self, event):
self.next_box = False
if self.data_check:
self.data_check = False
x = float(self.active_widget.get())
if x == "":
messagebox.showinfo(title="Blank Entry", message="You must enter a number.")
self.active_widget.focus_set()
else:
try:
x
if x < 10.0 or x > 15.0:
messagebox.showinfo(title="Out of Range", message=x + " is not between 10-15")
self.active_widget.focus_set()
except ValueError:
messagebox.showinfo(title="Not Numeric", message=x + " is not a valid number.")
self.active_widget.focus_set()
if not self.next_box:
self.next_box = True
self.data_check = True
else:
self.active_widget.focus_set()
self.data_check = True
def focus_in(self, event):
if self.next_box:
self.active_widget = self.focus_get()
self.data_check= True
else:
self.next_box = True
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
|