Reputation: 271
I want to use the most efficient way to limit the user not to enter anything than digits. For example: when they input a letter in an entry, that exact entry gets cleared. Is there any way to do it with the least changes in the structure?
Here is my code:[the ????? sign is where I'm stuck]
import tkinter as tk
from tkinter import ttk
class App:
"""Main class for a simple application"""
def __init__(self, master):
"""Main initialisation for the main app"""
# create a top frame or window which we can add things to it
self.topFrame = tk.Frame(master)
self.topFrame.pack()
# create a holder (notebook) for tabs
self.note = ttk.Notebook(self.topFrame)
# create four different tabs for the main screen
self.tab1 = ttk.Frame(self.note)
self.tab2 = ttk.Frame(self.note)
self.tab3 = ttk.Frame(self.note)
self.tab4 = ttk.Frame(self.note)
# add four different tabs for the main screen with various names
self.note.add(self.tab1, text=' Demography ')
self.note.add(self.tab2, text=' Urban Economy ')
self.note.add(self.tab3, text=' Land Use ')
self.note.add(self.tab4, text=' Urban Transportation ')
self.note.pack()
# add a frame to each tab
self.demog_frame = tk.Frame(self.tab1)
self.demog_frame.pack()
self.eco_frame = tk.Frame(self.tab2)
self.eco_frame.pack()
self.land_frame = tk.Frame(self.tab3)
self.land_frame.pack()
self.trans_frame = tk.Frame(self.tab4)
self.trans_frame.pack()
# add label frames to {DEMOGRAPHY TAB}
self.demog_flable_1 = tk.LabelFrame(self.demog_frame, text='Population Growth:')
self.demog_flable_1.grid(row=0, column=0, ipadx=0, ipady=10, padx=0)
# add info to the first LabelFrame
self.d_p_grwt_label_fy = tk.Label(self.demog_flable_1, text='population of year n |', pady=0, font='Arial 8')
self.d_p_grwt_label_fy.grid(row=0, column=0)
self.d_p_grwt_label_sy = tk.Label(self.demog_flable_1, text='population of year n+1 |', font='Arial 8')
self.d_p_grwt_label_sy.grid(row=0, column=1)
self.d_p_grwt_label_fyy = tk.Label(self.demog_flable_1, text='year n eg:1999 |', font='Arial 8')
self.d_p_grwt_label_fyy.grid(row=2, column=0)
self.d_p_grwt_label_syy = tk.Label(self.demog_flable_1, text='year n+1 eg:2006 |', font='Arial 8')
self.d_p_grwt_label_syy.grid(row=2, column=1)
self.d_p_grwt_entry_fy = tk.Entry(self.demog_flable_1, width=12)
self.d_p_grwt_entry_fy.bind("<KeyRelease>", func=self.popfunc_1)
self.d_p_grwt_entry_fy.grid(row=1, column=0)
self.d_p_grwt_entry_sy = tk.Entry(self.demog_flable_1, width=12)
self.d_p_grwt_entry_sy.grid(row=1, column=1)
self.d_p_grwt_entry_fyy = tk.Entry(self.demog_flable_1, width=12)
self.d_p_grwt_entry_fyy.grid(row=3, column=0)
self.d_p_grwt_entry_syy = tk.Entry(self.demog_flable_1, width=12)
self.d_p_grwt_entry_syy.grid(row=3, column=1)
#----------------------------------------------
self.d_p_grwt_dscrpt_label = tk.Label(self.demog_flable_1, text='population absolute change \u2193', font='Arial 8')
self.d_p_grwt_dscrpt_label.grid(row =0, column=2)
self.d_p_grwt_dscrpt_label1 = tk.Label(self.demog_flable_1, text='population annual absolute change \u2193', font='Arial 8')
self.d_p_grwt_dscrpt_label1.grid(row =2, column=2)
self.d_p_grwt_dscrpt_label2 = tk.Label(self.demog_flable_1, text='population annual percent change \u2193', font='Arial 8')
self.d_p_grwt_dscrpt_label2.grid(row =4, column=2)
def popfunc_1(self, *args):
try:
p1 = int(self.d_p_grwt_entry_fy.get())
p2 = int(self.d_p_grwt_entry_sy.get())
y1 = int(self.d_p_grwt_entry_fyy.get())
y2 = int(elf.d_p_grwt_entry_syy.get())
print(x1)
except ValueError:
????
root = tk.Tk()
root.title('Urban Calculator')
root.geometry('420x200')
app = App(root)
root.mainloop()
At the bottom of the class, I tried to except strings by ValueError
. If I write a pass
it is good but I want the entry to be cleared too. Is there any way to point to p1
or p2
and say whichever causes the error to be cleared?
Upvotes: 1
Views: 57
Reputation: 15226
Is there any way to point to p1 or p2 and say whichever causes the error to be cleared?
Yes but not all at once. You would have to run you try/except on each entry individually.
For example you could load your entry fields into a list and then use a loop to bind each entry to your method and then use the event that is passed to interact with the widget.
See below example and let me know if you have any questions.
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Urban Calculator')
self.geometry('420x200')
topFrame = tk.Frame(self)
topFrame.pack()
note = ttk.Notebook(topFrame)
tab1 = ttk.Frame(note)
note.add(tab1, text=' Demography ')
note.pack()
demog_frame = tk.Frame(tab1)
demog_frame.pack()
demog_flable_1 = tk.LabelFrame(demog_frame, text='Population Growth:')
demog_flable_1.grid(row=0, column=0, ipadx=0, ipady=10, padx=0)
tk.Label(demog_flable_1, text='population of year n |', pady=0, font='Arial 8').grid(row=0, column=0)
tk.Label(demog_flable_1, text='population of year n+1 |', font='Arial 8').grid(row=0, column=1)
tk.Label(demog_flable_1, text='year n eg:1999 |', font='Arial 8').grid(row=2, column=0)
tk.Label(demog_flable_1, text='year n+1 eg:2006 |', font='Arial 8').grid(row=2, column=1)
entry_list = [tk.Entry(demog_flable_1, width=12),
tk.Entry(demog_flable_1, width=12),
tk.Entry(demog_flable_1, width=12),
tk.Entry(demog_flable_1, width=12)]
entry_list[0].grid(row=1, column=0)
entry_list[1].grid(row=1, column=1)
entry_list[2].grid(row=3, column=0)
entry_list[3].grid(row=3, column=1)
for entry in entry_list:
entry.bind("<KeyRelease>", func=self.popfunc_1)
tk.Label(demog_flable_1, text='population absolute change \u2193', font='Arial 8').grid(row=0, column=2)
tk.Label(demog_flable_1, text='population annual absolute change \u2193',
font='Arial 8').grid(row=2, column=2)
tk.Label(demog_flable_1, text='population annual percent change \u2193',
font='Arial 8').grid(row=4, column=2)
def popfunc_1(self, event):
x = event.widget.get()
try:
entry_value = int(x)
print(entry_value)
except ValueError:
print('error')
event.widget.delete(len(x) - 1, 'end')
if __name__ == '__main__':
App().mainloop()
Upvotes: 1