Function not working as intended, python, TKinter - python

Im having trouble calling an variable from a function within another function.
I have two functions:
def refineRate(event):
if refineRate(event) == int():
refine = int(refineRate(event))
return refine
else:
refine = float(refineRate(event))
return refine
and:
def veldCalc(event):
minValue = open("mineral_value.csv", "r")
veld = minValue.readlines()[0]
minValue.close()
veld = veld[0:3]
veld = int(veld)
veld = veld / 100 * refineRate(event)
refinedVeld = veld * int(veldCalc)
print (refinedVeld)
I also have two entry where the user of the calculator can enter some figures.
repro = Label(root, text="Reprocessing %")
repro_entry = Entry(root)
repro.grid(row=0, column=0)
repro_entry.grid(row=0, column=1)
veld = Label(root, text="Veldspar: ")
veld_entry = Entry(root)
veld.grid(row=1, column=0)
veld_entry.grid(row=1, column=1)
repro_entry.bind("<KeyPress>", refineRate)
veld_entry.bind("<KeyPress>", veldCalc)
What i need is for the user to input there refineRate and which should then get passed through the function and stored for later use. the when they enter the amount they have, the veldCalc function should then pull the users refine rate from the previous function and do the math but im getting the following errors
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Ganjena\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:/Users/Ganjena/Desktop/Course/Projects/helloworld/ORE FUNCTIONS/Ore Calculator.py", line 5, in refineRate
if refineRate(event) == int():
File "C:/Users/Ganjena/Desktop/Course/Projects/helloworld/ORE FUNCTIONS/Ore Calculator.py", line 5, in refineRate
if refineRate(event) == int():
File "C:/Users/Ganjena/Desktop/Course/Projects/helloworld/ORE FUNCTIONS/Ore Calculator.py", line 5, in refineRate
if refineRate(event) == int():
[Previous line repeated 990 more times]
RecursionError: maximum recursion depth exceede
any idea to why this isn't working? Thank you in advance.

You seem to have a misconception of how to get the user-input value inside a tk.Entry widget. The proper way is to use the .get() method on the widget.
Here is a minimal example to get you started:
# (Use Tkinter/tkinter depending on Python version)
import Tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.repro = tk.Label(self, text="Reprocessing %")
self.repro_entry = tk.Entry(self)
self.repro.grid(row=0, column=0)
self.repro_entry.grid(row=0, column=1)
self.repro_entry.bind("<Return>", self.refineRate)
self.mainloop()
def refineRate(self, evt):
# Get the user input and print it in the terminal
userRepro = self.repro_entry.get()
print(userRepro)
# Launch the GUI
app = App()
Then, to check whether the user input is a float or an int, you can use the technique described in this link.

Related

What causes an exception in Tkinter callback? [duplicate]

This question already has an answer here:
TypeError: 'NoneType' object is not callable with tkinter
(1 answer)
Closed 1 year ago.
I'm trying to make a program that you can add infinite rooms to, so all of my code is built around using one variable to deduce which room is which. However when I run it, it gives me an error that doesn't directly reference any one line in my code, and since I'm a pretty new programmer, I don't know what it means. Also my code is pretty all over the place and incomplete. Thanks for any help!
The error
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\SCA0023\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
TypeError: 'NoneType' object is not callable
The Code
from tkinter import *
root = Tk()
class Room:
def __init__(self, items):
self.objects = []
self.objects.append(items)
def list(self):
print(self.objects)
def addkitchenmenu(r): #add a new option menu attributed to a new room
globals()[f'kitchenvar_{r}'] = StringVar(root)
globals()[f'kitchenvar_{r}'].set("Add an appliance")
globals()[f'kitchenvar_{r}'].trace('w', applianceadd(r))
kitchenitems = ['Kettle', 'Toaster']
globals()[f'appliancelist_{r}'] = OptionMenu(root, globals()[f'kitchenvar_{r}'], *kitchenitems).pack()
addkitchen(r)
def applianceadd(r): #add a new room
globals()[f'kobjects_{r}'] = []
globals()[f'kobjects_{r}'].append(globals()[f'kitchenvar_{r}'].get())
items = globals()[f'kobjects_{r}']
globals()[f'kroom_{r}'] = Room(items)
globals()[f'kroom_{r}'].list()
def addkitchen(r): #add an appliance
globals()[f'addappliace{r}'] = Button(root, text='add appliance', command=lambda: applianceadd(r))
def newkitchencheck(): #find the next name for a room that isn't taken
varnotfound = True
a = 0
while varnotfound:
if f'kroom{a}' in globals():
a += 1
else:
r = a
varnotfound = False
addkitchenmenu(r)
addroombutton = Button(root, text="add kitchen", command=newkitchencheck)
addroombutton.pack()
root.mainloop()
You are passing result of applianceadd(r) (which is None) to .trace(). Change to .trace("w", lambda *_: applianceaddr(r)).

Passing arguments down in Tkinter to a method

I'm struggling to get my method working correctly. I've thought about using a lambda function which I did for another problem and that worked, however here it does not seem to work. I'm trying to change the functions to methods and for some reason, my method is not working correctly since it has no reference to the tree. I've tried using a lambda function although that does not work.
My error:
NameError: name 'tree' is not defined
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
return self.func(*args)
File "/home/bitvivaz/Documents/Software Development/Python/PasswordManager/mainFrame.py", line 54, in select
print([tree.item(x) for x in tree.selection()])
NameError: name 'tree' is not defined
Here is my code:
import tkinter as tk
import tkinter.ttk as ttk
from encryption import encrypted_password, decrypt_password
import backend as db
def get_credentials(tree):
'''Retrieves all credentials from the database and inserts it into the tree widget'''
for row in db.show_credentials():
tree.insert("", 'end', text=row['name'], values=(
row['username'], decrypt_password(row['password'])))
class MainframeApp:
def __init__(self, master=None):
# build ui
frame_main = ttk.Frame(master)
frame_main.config(height='600', width='600')
frame_main.grid()
# Creates tree widget
tree = ttk.Treeview(frame_main)
tree["columns"] = ("one", "two")
tree.column("#0")
tree.column("one")
tree.column("two")
tree.heading("#0", text="Website")
tree.heading("one", text="Username")
tree.heading("two", text="Password")
tree.grid(padx='5', pady='5', rowspan='20')
get_credentials(tree)
tree.bind("<<TreeviewSelect>>", self.select, "+")
button_add = ttk.Button(frame_main)
button_add.config(text='Add')
button_add.grid(column='1', padx='5', row='0')
button_delete = ttk.Button(frame_main)
button_delete.config(text='Delete')
button_delete.grid(column='1', padx='5', row='1')
button_logout = ttk.Button(frame_main)
button_logout.config(text='Logout')
button_logout.grid(column='1', padx='5', row='2')
# Main widget
self.mainwindow = frame_main
def select(self, e):
print([tree.item(x) for x in tree.selection()])
def run(self):
self.mainwindow.mainloop()
if __name__ == '__main__':
root = tk.Tk()
root.title("Password Manager")
app = MainframeApp(root)
app.run()
When you make use of a class structure, certain variables are available across methods (class or instance variables), others are not (local variables).
In your case, you need to define variables you need across methods as instance variables, that is, rather than:
tree = ttk.Treeview(frame_main)
You declare:
self.tree = ttk.Treeview(frame_main)
Then you can reference the variable across methods as self.tree.

AttributeError when using validatecommand on a Spinbox

I am doing a test writing a script that validate a spinbox to implement it on a larger system, but I am struggling with python because it is warning that there is no spinbox attribute on my Window class. Check my code:
from Tkinter import *
class Window:
def __init__(self, toplevel):
self.spinbox = Spinbox(toplevel, from_ = 0, to = 10,
validate = 'all', validatecommand = self.validate)
self.spinbox.pack()
def validate(self):
print self.spinbox.get()
root = Tk()
Window(root)
root.mainloop()
This is the error it is giving:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1486, in __call__
return self.func(*args)
File "D:\DOCS\FILIPE\PROGRAMMING\PYTHON\Tkinter sandbox\01 - spinbox validate.
py", line 13, in validate
print self.spinbox.get()
AttributeError: Window instance has no attribute 'spinbox'
Anyone could help me with this one?
If you add some print statements to your code:
class Window:
def __init__(self, toplevel):
print "A start", self, self.__dict__
self.spinbox = Spinbox(toplevel, from_ = 0, to = 10,
validate = 'all', validatecommand = self.validate)
self.spinbox.pack()
print "A end", self, self.__dict__
def validate(self):
print "B", self, self.__dict__
print self.spinbox.get()
#...
You get the output:
A start <__main__.Window instance at 0x7fe4f8deec20> {}
B <__main__.Window instance at 0x7fe4f8deec20> {}
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1532, in __call__
return self.func(*args)
File "t.py", line 14, in validate
print self.spinbox.get()
AttributeError: Window instance has no attribute 'spinbox'
A end <__main__.Window instance at 0x7fe4f8deec20> {'spinbox': <Tkinter.Spinbox instance at 0x7fe4f8e0da28>}
This means that the validate function is called inside the constructor to validate the initial value, and at that point self.spinbox has not yet been set. You will need to either check if you are still constructing or delay setting validatecommand like this:
self.spinbox = Spinbox(toplevel, from_ = 0, to = 10,
validate = 'all')
self.spinbox["validatecommand"] = self.validate
self.spinbox.pack()
I MANAGED TO SOLVE THE PROBLEM USING TEXTVARIABLES AND THE TRACE METHOD
#Validates
self.countstringvar = StringVar()
self.countstringvar.trace("w", lambda name, index, mode,
sv = self.countstringvar: self.noLettersValidate(sv, self.count))
self.starsstringvar = StringVar()
self.starsstringvar.trace("w", lambda name, index, mode,
sv = self.starsstringvar: self.noLettersValidate(sv, self.stars))
self.scorestringvar = StringVar()
self.scorestringvar.trace("w", lambda name, index, mode,
sv = self.scorestringvar: self.noLettersValidate(sv, self.score))
self.count['textvariable'] = self.countstringvar
self.stars['textvariable'] = self.starsstringvar
self.score['textvariable'] = self.scorestringvar
def removeLetters(self, s):
a = []
for i in s:
if i.isdigit():
a.append(i)
return ''.join(a)
def noLettersValidate(self, sv, w):
w.text(self.removeLetters(sv.get()))
Thanks for everyone contributions!

Timer App Type Error I Can't See

I'm quite new to python I have run into a type error but I personally can't see it. Help will be appreciated. I am using windows 7.
Error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "C:\Users\Kids\Desktop\Python Tests\Clock2.py", line 18, in mclock
mlable = Label(mGui, str(z), "minute(s) has past.").pack()
TypeError: __init__() takes from 1 to 3 positional arguments but 4 were given
Code:
import sys
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
import os
from time import sleep
def mclock():
x = 1
z = 0
while x != -1:
mlable = Label(mGui,text = "str(x) second(s)").pack()
x = x+1
sleep(1)
if x == 60:
x = 1
z = z+1
mlable = Label(mGui, str(z), "minute(s) has past.").pack()
return
mGui = Tk()
mGui.geometry("300x200+100+100")
mGui.title("Jono's Clock")
menubar = Menu(mGui)
filemenu = Menu(menubar, tearoff = 0)
filemenu.add_command(label = "Clock",command = mclock)
menubar.add_cascade(label = "File",menu = filemenu)
mGui.config(menu = menubar)
mGui.mainloop()
Also if any one knows haw to add a clear function to clear the seconds each time it ticks that will be appreciated as well.
The label initializer, like all Python methods, has a self first arguments. It accepts only up to two additional positional arguments (the master and cfg arguments), but you are giving 3:
Label(mGui, str(z), "minute(s) has past.")
You probably wanted to concatenate those two strings; you'll have to pass this in explicitly as the text keyword argument:
Label(mGui, text=str(z) + " minute(s) has past.")

Edit; tkinter weight converter

If i input an integer i get invalid. I want it to do invalid if its not a number 0 or greater. Any help greatly appreciated!
from Tkinter import *
import tkMessageBox
from Tkinter import *
import tkMessageBox
class MyApp(object):
def __init__(self):
self.root = Tk()
self.root.wm_title("Question 7")
self.label = Label(self.root, text="Enter weight in pounds",
font=('Calibri', 50))
self.label.pack(padx=20,pady=10)
self.labeltext = StringVar()
self.labeltext.set("")
Label(self.root, textvariable=self.labeltext).pack()
self.entrytext = StringVar()
Entry(self.root, textvariable=self.entrytext).pack()
self.entrytext.trace('w', self.entry_changed)
self.root.mainloop()
def entry_changed(self, a, b, c):
s = self.entrytext.get()
try:
a=int(s)*4.3
self.labeltext.set(a)
The problem is the first boolean condition. The condition is evaluating as true
>>> 'Not A Number' >= 0
True
However, when it then goes to cast it as an integer, it fails:
>>> int('Not A Number')
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
int('Not A Number')
ValueError: invalid literal for int() with base 10: 'Not A Number'
Try this instead so you can properly catch and manage the exception that is being caused:
def entry_changed(self, a, b, c):
s = self.entrytext.get()
try:
a=int(s)*4.3
self.labeltext.set(a)
except:
if s=="":
self.labeltext.set("")
else:
self.labeltext.set("invalid")
Note, that when the user enters a float eg. 4.3 it will also generate an exception so you might want to correct that too.

Categories