I have a problem to check the range and type of the entry values using .get: "AttributeError: 'float' object has no attribute 'get'"

Hi,
I expect that the below code build a GUI window and get three parameters from user, check the range of parameter 1 (which should be between 0 and 1), and handle any unacceptable value using a warning message box. However, if the entered value is out of range, the below error appears. Do you have any idea? Besides, how could I check the entered values for type and acceptable characters (i.e. double and integer values).
Thanks.

import tkinter
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
w1 = Tk()
w1.geometry("300x200")
w1.title("Window 1")
lblw1 = Label(w1, text="Set the values:", font=('default', 10, 'bold'))
lblw1.grid(row=1, column=1, padx=5, pady=5, sticky=S)
ent1w1 = DoubleVar()
ent2w1 = IntVar()
ent3w1 = IntVar()
ent1w1.set(0.1)
ent2w1.set(40)
ent3w1.set(220)

def entw1():
    global ent1w1, ent2w1, ent3w1
    ent1w1 = ent1w1.get()
    ent2w1 = ent2w1.get()
    ent3w1 = ent3w1.get()
    while "0" >= str(ent1w1) or str(ent1w1) >= "1":
        tkinter.messagebox.showwarning(title='Error!', message='Please enter a value between 0 and 1')
        ent1w1 = ent1w1.get()
    print("P1=",ent1w1, " P2=",ent2w1, " P3=",ent3w1)
    w1.destroy()

p1w1_lable = tkinter.Label(w1, text='Parameter1')
p1w1_ent = tkinter.Entry(w1, textvariable=ent1w1, borderwidth=3, width=6)
p2w1_lable = tkinter.Label(w1, text='Parameter2')
p2w1_ent = tkinter.Entry(w1, textvariable=ent2w1, borderwidth=3, width=6)
p3w1_lable = tkinter.Label(w1, text='Parameter3')
p3w1_ent = tkinter.Entry(w1, textvariable=ent3w1, borderwidth=3, width=6)

w1OK = ttk.Button(w1, text="OK", command=entw1)
w1OK.grid(row=9, column=1, columnspan=1, rowspan=10, padx=40, pady=20, sticky=S)

w1Cancel = ttk.Button(w1, text="Cancel", command=quit)
w1Cancel.grid(row=9, column=2, columnspan=1, rowspan=10, padx=40, pady=20, sticky=S)

p1w1_lable.grid(row=4, column=1, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p1w1_ent.grid(row=4, column=2, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p2w1_lable.grid(row=5, column=1, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p2w1_ent.grid(row=5, column=2, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p3w1_lable.grid(row=6, column=1, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p3w1_ent.grid(row=6, column=2, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
w1.eval('tk::PlaceWindow . center')
w1.mainloop()

Error:
Exception in Tkinter callback
Traceback (most recent call last):
File “C:\Users.…_init_.py”, line 1921, in call
return self.func(*args)
File “C:\Users.…\temp.py”, line 24, in entw1
ent1w1 = ent1w1.get()
AttributeError: ‘float’ object has no attribute ‘get’

Try commenting out these lines:

    ent1w1 = ent1w1.get()
    ent2w1 = ent2w1.get()
    ent3w1 = ent3w1.get()

and the one in the while loop.

You’ve already called .get on them, which presumably returns a Python native float. But ttk.Button that you passed the entw1 to might call .get on DoubleVars itself.

1 Like

Thanks. Moreover, I can’t understand that why the “while” and also “if” statements results in wrong outputs. The statements do not give correct answers.

What do you think str(ent1w1) does?

In your original code, you had ent1w1 refer to a tk variable, but then did ent1w1 = ent1w1.get(), which ‘overwrote’ the reference to the tk variable with the value contained within it.

Deleting ent1w1 = ent1w1.get() stopped that, but that means that ent1w1 still refers to the tk variable, so you need to change str(ent1w1) to str(ent1w1.get())…

… well, except that comparing the values as strings in this case is a strange thing to do.

You want to know whether the value in ent1w1 is numerically between 0 and 1, so you should compare them as numbers: while 0 >= ent1w1.get() or ent1w1.get() >= 1:.

That can be written more clearly with not and a ‘chained comparison’: while not 0 < ent1w1.get() < 1:. (x < y < z is equivalent to x < y and y < z, but y is evaluated only once.)

Incidentally, you say “between 0 and 1”, should 0 and 1 be accepted (inclusive range) or rejected (exclusive range)? If it’s an inclusive range, then use while not 0 <= ent1w1.get() <= 1: instead.

1 Like

Thank you for your comprehensive answer. As a beginner, I had reached String, following system suggestions for error correction! Now, based your comments, I have changed the code as below. Since the while (or while not) statement led to a non-stop loop i.e. the warning box was shown continuously, I replaced it by" if not". Please let me know if you have further suggestions.

import tkinter
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
w1 = Tk()
w1.geometry("300x200")
w1.title("Window 1")
lblw1 = Label(w1, text="Set the values:", font=('default', 10, 'bold'))
lblw1.grid(row=1, column=1, padx=5, pady=5, sticky=S)
ent1w1 = DoubleVar()
ent2w1 = IntVar()
ent3w1 = IntVar()
ent1w1.set(0.1)
ent2w1.set(40)
ent3w1.set(220)

def entw1():
    global ent1w1, ent2w1, ent3w1
    if not 0 <= ent1w1.get() <= 1:
        tkinter.messagebox.showwarning(title='Error!', message='Please enter a value between 0 and 1')
        ent1w1.set(0.1)
    else:
        print("P1=",ent1w1.get(), " P2=",ent2w1.get(), " P3=",ent3w1.get())
        w1.destroy()

p1w1_lable = tkinter.Label(w1, text='Parameter1')
p1w1_ent = tkinter.Entry(w1, textvariable=ent1w1, borderwidth=3, width=6)
p2w1_lable = tkinter.Label(w1, text='Parameter2')
p2w1_ent = tkinter.Entry(w1, textvariable=ent2w1, borderwidth=3, width=6)
p3w1_lable = tkinter.Label(w1, text='Parameter3')
p3w1_ent = tkinter.Entry(w1, textvariable=ent3w1, borderwidth=3, width=6)

w1OK = ttk.Button(w1, text="OK", command=entw1)
w1OK.grid(row=9, column=1, columnspan=1, rowspan=10, padx=40, pady=20, sticky=S)

w1Cancel = ttk.Button(w1, text="Cancel", command=quit)
w1Cancel.grid(row=9, column=2, columnspan=1, rowspan=10, padx=40, pady=20, sticky=S)

p1w1_lable.grid(row=4, column=1, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p1w1_ent.grid(row=4, column=2, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p2w1_lable.grid(row=5, column=1, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p2w1_ent.grid(row=5, column=2, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p3w1_lable.grid(row=6, column=1, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
p3w1_ent.grid(row=6, column=2, columnspan=1, rowspan=1, padx=1, pady=2, sticky=S)
w1.eval('tk::PlaceWindow . center')
w1.mainloop()

You’re right about the while loop.

On a style note, it’s better to put the positive condition first, i.e. if it’s ok then print and close dialog else complain.

Also, you don’t need to declare that ent1w1, etc, are global because you’re not assigning to them in the function.

1 Like

Thanks; even if I should use ent1w1 in the next sections of the code (not shared), I can remove global?

If you assign to a name in a function, Python assumes that the name is local to the function unless you declare that it’s global or nonlocal.

If you don’t assign to a name in a function, then Python assumes that the name comes from outside the function.

In your function entw1, you’re not assigning to entw1 and the others, therefore entw1 and the others are from outside the function, so it’s not necessary to say that they’re global.

1 Like