Python tkinter trace error - python

I'm trying to write a GUI for my code. My plan is to use tkinter's StringVar, DoubleVar, etc. to monitor my input in real time. So I found out the DoubleVar.trace('w', callback) function. However, every time I make the change I get an exception:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Anaconda2\lib\lib-tk\Tkinter.py", line 1542, in __call__
return self.func(*args)
TypeError: 'NoneType' object is not callable
I have no idea what's going wrong. I'm using python 2.7
My code is as follows:
from Tkinter import *
class test(Frame):
def __init__(self,master):
Frame.__init__(self,master=None)
self.main_frame = Frame(master);
self.main_frame.pack()
self.testvar = DoubleVar()
self.slider_testvar = Scale(self.main_frame,variable = self.testvar,from_ = 0.2, to = 900, resolution = 0.1, orient=HORIZONTAL,length = 300)
self.slider_testvar.grid(row = 0, column = 0, columnspan = 5)
self.testvar.trace('w',self.testfun())
def testfun(self):
print(self.testvar.get())
root = Tk()
root.geometry("1024x768")
app = test(master = root)
root.mainloop()

Consider this line of code:
self.testvar.trace('w',self.testfun())
This is exactly the same as this:
result = self.testfun()
self.testvar.trace('w', result)
Since the function returns None, the trace is going to try to call None, and thus you get 'NoneType' object is not callable
The trace method requires a callable. That is, a reference to a function. You need to change that line to be the following (notice the missing () at the end):
self.testvar.trace('w',self.testfun)
Also, you need to modify testfun to take arguments that are automatically passed by the tracing mechanism. For more information see What are the arguments to Tkinter variable trace method callbacks?

Related

curselection() missing 1 required positional argument: 'self'

lbox = Listbox
def Show():
Selected=lbox.get(lbox.curselection())
with open("pass.json","r+") as jfile:
try:
data=json.load(jfile)
for i in data['Details']:
if Selected==i["Site"]:
password_text.set(i["Password"])
uname_text.set(i["Username"])
except JSONDecodeError:
pass
I wanted to use curselection() but curselection() missing 1 required positional argument: 'self' is coming all the time
lbox was declared in another function which is given below
def Show_fun():
newWindow=Toplevel(window)
newWindow.title("Show your stuff")
newWindow.geometry("600x400")
Label(newWindow,text="Show passwords").grid(row=0,column=1,pady=10)
Label(newWindow,text="Site name : ").grid(row=1,pady=10)
lbox=Listbox(newWindow)
lbox.grid(row=1,column=2)
sites=[]
with open("pass.json","r+") as jfile:
try:
data=json.load(jfile)
for i in data['Details']:
sites.append(i["Site"])
except JSONDecodeError:
pass
lbox.config(height=lbox.size())
for i in sites:
lbox.insert(lbox.size(),i)
#site_entry = Entry(newWindow,textvariable = site_text,width=20,state=DISABLED).grid(row=1,column=2)
Label(newWindow,text="Username : ").grid(row=2,pady=10)
uname_entry=Entry(newWindow,textvariable=uname_text,state=DISABLED).grid(row=2,column=2)
Label(newWindow,text="Password : ").grid(row=3,pady=10)
pasword_entry=Entry(newWindow,textvariable=password_text,width=20,state=DISABLED).grid(row=3,column=2)
Button(newWindow,text="Show",command=Show,fg="#00FF00",bg="black",pady=10).grid(row=4,column=1)
I saw many YT vids . ListBox was working globally but in my its not working globally
EDIT: after giving parenthesis to ListBox() New error arises
Traceback (most recent call last):
File "C:\Program Files\Python38\lib\tkinter\__init__.py", line 1895, in __call__
return self.func(*args)
File "d:/Python files/cybersecurity/password manager/password_test.py", line 24, in Show
Selected=lbox.get(lbox.curselection())
File "C:\Program Files\Python38\l`enter code here`ib\tkinter\__init__.py", line 3190, in get
return self.tk.call(self._w, 'get', first)
_tkinter.TclError: bad listbox index "": must be active, anchor, end, #x,y, or a number
The error message simply means that the method was not invoked on the object but on the class instead. In the first code snippet, you didn't seem to instantiate a ListBox object.
You must change the line
lbox = Listbox
to something like:
# Tkinter window object
window = Tk()
# Create ListBox object and bind to the Tkinter window
lbox = Listbox(window)
In the above snippet, an instance of ListBox is created on which the method curselection() could be called. Give more emphasis to the argument passed to ListBox. The window variable used above is an instance of the Tk class which essentially constructs the Tkinter window. Without this argument, the listbox widget won't know which window it must bind to.

Insert string to tkinter text widget from other thread

I've read at least 25 similar questions on this site, and I simply cannot get this working.
As it stands i'm just trying to build a simple chat app with a client and server. The GUI will be running on a separate thread to the logic to ensure things stay fluid and don't lock up. I've trimmed most of the logic out of the code to isolate the problem
import socket, csv, datetime, tkinter as tk, threading
from tkinter import ttk
interface = tk.Tk()
test = tk.StringVar()
test.set("String Var Test")
class serverInterface():
def __init__(self, interface):
global test
self.messageLog = tk.Text(interface, height=10, state="disabled", yscrollcommand="scrollBar.set")
self.scrollBar = ttk.Scrollbar(interface, command=self.messageLog.yview).grid(row=0, column=2, sticky="nsew")
self.messageLog.grid(row=0, column=0, columnspan=2)
test.trace("w", serverInterface.guiUpdate(self))
def guiUpdate(self):
self.messageLog.insert(tk.END, test)
class server():
def __init__(self):
global test
print("Server thread")
while True:
test.set("Updated from server object")
interface.title("Server")
serverInterface = threading.Thread(target=serverInterface(interface)) #Create serverInterface object
server = threading.Thread(target=server, daemon=True) # Create server object
server.start()
interface.mainloop()
This results in the console being spammed with Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\thoma\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__ return self.func(*args) TypeError: 'NoneType' object is not callable
I've also tried to make use of Queue() as I've seen others suggest, but that just results in a different set of errors and I feel using StringVar() is probably the better way of doing this.
I appreciate that there's probably some lines in this code that don't need to be there, they're just leftovers from all the different attempts at bodging it :/
Any solutions would be appreciated.
The error you're asking about is due to this line:
test.trace("w", serverInterface.guiUpdate(self))
That line is functionally identical to this:
result = serverInterface.guiUpdate(self)
test.trace("w", result)
Since guiUpdate(self) returns None, you're asking tkinter to call None. Hence the error TypeError: 'NoneType' object is not callable
The trace method must be given a callable (ie: a reference to a function). In this specific case you need to use self.guiUpdate.
The trace will automatically pass arguments to the function, so you need to properly define the function to accept those arguments. You also have a bug where you're trying to insert an object (test) in the text widget rather than the text contained in the object.

Calling an object method using a function

I am playing around tkinter, and I was wondering if I had declared a method within an object, can I call it using the 'protocol' method of tkinter? or any function to be exact ie.
class Notepad():
...
...
def exit_func():
#Messagebox command warning 'You are exiting'
root = tk.Tk()
notepad = Notepad(root)
root.geometry("800x500")
root.mainloop()
#Problem is here
root.protocol("WM_DELETE_WINDOW", app.exit_func())
I tried this with my program, where my 'exit_func' had a 'get' function from tkinter and i got this error:
Traceback (most recent call last):
File "Notepad_with_console.py", line 204, in <module>
root.protocol("WM_DELETE_WINDOW", notepad.exit_file())
File "Notepad_with_console.py", line 175, in exit_file
if self.text.get(1.0,tk.END) != '' and self.current_file_dir == '':
File "C:\Anaconda\lib\tkinter\__init__.py", line 3246, in get
return self.tk.call(self._w, 'get', index1, index2)
_tkinter.TclError: invalid command name ".!text"
Is there a reason for this? Thanks!
root.protocol requires a reference to a function. Instead, you're immediately calling a function and then passing in the result.
Consider this code:
root.protocol("WM_DELETE_WINDOW", app.exit_func())
That code is functionally identical to this:
result = app.exit_func()
root.protocol("WM_DELETE_WINDOW", result)
Instead, you need to pass in a reference to the function:
root.protocol("WM_DELETE_WINDOW", app.exit_func)

For loop inside a method : TypeError positional arguments

I'm trying to create a simple Gui with tkinter using classes.
But I don't really understand how to make the for-loop work inside the count method, could anyone tell me where should I add the missing argument?
from tkinter import *
import time
class App:
def __init__(self, master):
self.container1 = Frame(master)
self.container1.pack()
self.button1 = Button(self.container1, text="count")
self.button1.bind("<Button-1>", self.count)
self.button1.pack()
def count(self):
for i in range(100):
self.button1["text"] = str(i)
time.sleep(1)
root = Tk()
Myapp = App(root)
root.mainloop()
The error is:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/__init__.py", line 1553, in __call__
return self.func(*args)
TypeError: count() takes 1 positional argument but 2 were given
When you bind an event, a positional argument event is provided to the callback function.
Change your count method to this:
def count(self, event):
You will also need to get rid of time.sleep(1) since .sleep() is a blocking call, which means that it will block the tkinter mainloop which will cause your program to not respond.

root.after unable to find function_name

I am trying to put together a GUI that would read from a continuously updated TXT file and updated every once in a while. So far I succeeded with the first part and I am failing to use 'root.after()' to loop the whole thing but it results in NameError:
import tkinter as tk
root = tk.Tk()
class App:
def __init__(self, root):
frame = tk.Frame(root)
frame.pack()
iAutoInEN = 0
iAvailableEN = 0
self.tkAutoInEN = tk.StringVar()
self.tkAutoInEN.set(iAutoInEN)
self.tbAutoInEN = tk.Label(root, textvariable=self.tkAutoInEN)
self.tbAutoInEN.pack(side=tk.LEFT)
self.button = tk.Button(frame, text="Start", fg="red",
command=self.get_text)
self.button.pack(side=tk.LEFT)
def get_text(self):
fText = open("report.txt") #open a text file in the same folder
sContents = fText.read() #read the contents
fText.close()
# omitted working code that parses the text to lines and lines
# to items and marks them with numbers based on which they are
# allocated to a variable
if iLineCounter == 1 and iItemCounter == 3:
iAutoInEN = int(sItem)
self.tkAutoInEN.set(iAutoInEN)
root.after(1000,root,get_text(self))
app = App(root)
root.mainloop()
try:
root.destroy() # optional; see description below
except:
pass
The first instance runs without any problems and updates the value from 0 to the number in the TXT file but is accompanied with an error
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\...\Python35\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
File "C:/.../pythonlab/GUI3.py", line 117, in get_text
self.after(1000,root,get_text())
NameError: name 'get_text' is not defined
EDIT:
When changed to the recommended "self.after(1000,self.get_text)"
class App:
...
def get_text(self):
fText = open("report.txt") #open a text file in the same folder
sContents = fText.read() #read the contents
fText.close()
# omitted code
if iLineCounter == 1 and iItemCounter == 3:
iAutoInEN = int(sItem)
self.tkAutoInEN.set(iAutoInEN)
self.after(1000,self.get_text)
Error changes
Traceback (most recent call last):
File "C:/.../pythonlab/GUI3.py", line 6, in <module>
class App:
File "C:/.../pythonlab/GUI3.py", line 117, in App
self.after(1000, self.get_text)
NameError: name 'self' is not defined
Also please consider this is my very first programme (not only) in Python, so I would appreciate if you are a little bit more explicit with your answers (e.g. when pointing out an indentation error, please refer to an exact line of code).
Because get_text is a method of App class you should call it as self.get_text.
After is a tkinter method. In that case you should call it as root.after. And self refers to the class you are in. So because get_text is a method of current class you should call is with self which is like this in other programming languages like Java.
...
root.after(1000, self.get_text)
...
Firstly, like James commented, you should fix your indentation so that the functions are a part of the class.
Then, change this line
root.after(1000,root,get_text(self))
to this
root.after(1000, self.get_text)
Check out the answer to the following question, which uses the code I just gave you:
Tkinter, executing functions over time

Categories