第二次运行时,Tkinter会出错

时间:2013-12-04 10:38:03

标签: python tkinter

我使用Tkinter编写了一个GUI,第一次运行时工作正常。但是,在退出后我尝试再次运行它,我收到以下错误:

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"

我怀疑在运行用于修改stdput的代码时出现错误:该行封装在**中的问题。

    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

任何人都知道为什么会这样吗?

感谢您的回答。 完整代码添加:

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

1 个答案:

答案 0 :(得分:1)

这必须与spyder有关,或者与你如何设置重定向器有关。我对spyder一无所知,所以我不能肯定地说。问题的关键是,你在一个被破坏的小部件上调用一个方法。

我的猜测是你重定向stdout,然后你退出程序,但stdout仍然被重定向。因此,当spyder需要打印某些东西时,它会尝试去旧的标准输出。当它这样做时,它会尝试将数据插入到已被销毁的旧文本小部件中。