user2866103
user2866103

Reputation: 10555

Tkinter gives error when ran the second time

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

Answers (1)

Bryan Oakley
Bryan Oakley

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

Related Questions