Reputation: 10555
I have written a GUI using Tkinter, which works fine the first time i run it. However, after quitting I try to run it again, and I get the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Anaconda\lib\lib-tk\Tkinter.py", line 1470, in __call__
return self.func(*args)
File "G...tkinter_ny.py", line 55, in <lambda>
self.myRunModelButton=tk.Button(f1,text='Run Model', command=lambda: self.BeregnModel(), width=15, height=4)
File "G...tkinter_ny.py", line 115, in BeregnModel
sl.sim(self.model,self.data,'2013Q3','2015Q4')
File "stresslos.py", line 115, in sim
print (period,' solved')
File "G...tkinter_ny.py", line 39, in write
**self.text_area.insert(tk.END, str)**
File "C:\Anaconda\lib\lib-tk\Tkinter.py", line 3048, in insert
self.tk.call((self._w, 'insert', index, chars) + args)
TclError: invalid command name ".192096136L.192102984L"
I suspect the error comes when running a code for chaning the stdput: Where the line encapsulated in ** i the problem.
class StdoutRedirector(object):
def __init__(self, text_area):
self.text_area = text_area
def write(self, str):
**self.text_area.insert(tk.END, str)**
self.text_area.see(tk.END)
self.text_area.update() #to be added to get it in real time
Anyone know why this happens ?
Thanks for the answers. full code added:
import Tkinter as tk
import ttk as ttk
import pandabank as pb
import sys as sys
import subprocess as sp
class StresGUI(tk.Tk, ):
def __init__(self,inputData, inputModel):
tk.Tk.__init__(self)
# w,h=1000,900
# self.geometry("%dx%d+0+0" % (w, h))
self.grid()
self.title(The Name) #name of frame
#initializing data
self.data=pb.databank('')
self.data.set_data(inputData)
self.model=inputModel
self.selection = None
#self.frame=tk.Frame()
nb=ttk.Notebook(self)
nb.pack(fill='both', expand='yes')
#class redirect and update widgets with shell output in real time
class StdoutRedirector(object):
def __init__(self, text_area):
self.text_area = text_area
def write(self, str):
self.text_area.insert(tk.END, str)
self.text_area.see(tk.END)
self.text_area.update() #to be added to get it in real time
# create a child frame for each page
f1 = tk.Frame()
f2 = tk.Frame()
f3 = tk.Frame()
# create the pages
nb.add(f1, text='Solve models')
nb.add(f2, text='Bank information')
nb.add(f3, text='Treeview')
'''Adding items to frame 1 - Solve model'''
#put run model button on frame1
self.myRunModelButton=tk.Button(f1,text='Run Model', command=lambda: self.BeregnModel(), width=15, height=4)
self.myRunModelButton.pack(side=tk.TOP, fill=tk.BOTH)
#Quit program button on fram1
self.myQuitButton=tk.Button(f1,text='Quit', command=self.destroy,width=15, height=4)
self.myQuitButton.pack(side=tk.BOTTOM, fill=tk.BOTH)
outputPanel =tk.Text(f1, wrap='word', height = 25, width=40)
outputPanel1 =tk.Text(f2, wrap='word', height = 25, width=40)
outputPanel.pack(side=tk.BOTTOM)
outputPanel1.pack(side=tk.BOTTOM)
self.out1=StdoutRedirector(outputPanel)
self.out2=StdoutRedirector(outputPanel1)
sys.stdout = self.out1 #setting print output to frame1 initially
f1.bind("<Enter>",lambda e: self.useOut1()) #changig print output when entering the frame
f2.bind("<Enter>",lambda e: self.useOut2()) #changig print output when entering the frame
'''Adding items to frame 2 - Bank info'''
#plot values button
self.myPlotButton=tk.Button(f2,text='Plot values', command=lambda: self.PlotValues(self.data),width=15, height=4)
self.myPlotButton.pack(side=tk.TOP, fill=tk.BOTH)
#print values button
self.myPrintButton=tk.Button(f2,text='Print values', command=lambda:self.PrintValues(self.data),width=15, height=4)
self.myPrintButton.pack(side=tk.TOP, fill=tk.BOTH, anchor=tk.NW,before=self.myPlotButton)
#scrollbar for var selection
f2.scrollbar=ttk.Scrollbar(f2)
f2.scrollbar.pack(side=tk.RIGHT, fill=tk.BOTH)
lb = tk.Listbox(f2, yscrollcommand=f2.scrollbar.set, width=50)
for items in self.model.allvar:
lb.insert(tk.END,items)
lb.bind("<Double-Button-1>", self.SelectVar)
lb.pack(side=tk.LEFT, fill=tk.BOTH)
f2.scrollbar.config(command=lb.yview)
def SelectVar(self, event):
widget = event.widget
selection=widget.curselection()
value = widget.get(selection[0])
self.selection=value
def BeregnModel(self):
import stresslos as sl
try:
os.remove('los.pyc')
except:
pass
sl.simskriv(self.model)
sl.sim(self.model,self.data,'2013Q3','2015Q4')
def PlotValues(self,inputdata):
fig=inputdata.data[app.selection].plot()
return fig
def PrintValues(self,inputdata):
if app.selection == None:
print ('Please select variable to print')
else:
sp.call('cls',shell=True)
inputdata.print_item(app.selection)
def useOut1(self):
sys.stdout = self.out1
def useOut2(self):
sys.stdout = self.out2
if __name__ == "__main__":
app = StresGUI(data,model)
app.mainloop()T
Upvotes: 0
Views: 491
Reputation: 386285
This must have something to do with spyder, or with how you are setting up the redirector. I know nothing about spyder so I can't say for certain. The crux of the matter is, you're calling a method on a widget that has been destroyed.
My guess is that you're redirecting stdout, you then quit the program, but stdout is still redirected. So, when spyder needs to print something, it tries to go to the old stdout. When it does this, it tries to insert data into the old text widget which has been destroyed.
Upvotes: 1