Python:将stdout和stderr重定向到文本小部件会导致程序崩溃

Python:将stdout和stderr重定向到文本小部件会导致程序崩溃,python,python-2.7,python-3.x,tkinter,tk,Python,Python 2.7,Python 3.x,Tkinter,Tk,在程序崩溃后,我将stdout和stderr重定向到tkinter文本小部件,我认为这应该与缓冲问题有关 我应该如何进行 我制作了一个产生错误的可测试版本,以产生错误: 1-运行代码,按开始, 2-键入帮助并按Enter键(重复步骤(2)4-5次 或者更像是随机的) 将Tkinter作为tk导入 导入ttk 导入系统 进口稀土 导入线程 大字体=(“Verdana”,12) 标准字体=(“Verdana”,10) 小字体=(“Verdana”,8) cmdList=[“command1”, “

在程序崩溃后,我将stdout和stderr重定向到tkinter文本小部件,我认为这应该与缓冲问题有关 我应该如何进行

我制作了一个产生错误的可测试版本,以产生错误: 1-运行代码,按开始, 2-键入帮助并按Enter键(重复步骤(2)4-5次 或者更像是随机的)

将Tkinter作为tk导入
导入ttk
导入系统
进口稀土
导入线程
大字体=(“Verdana”,12)
标准字体=(“Verdana”,10)
小字体=(“Verdana”,8)
cmdList=[“command1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”,
“命令1”]
def gui_输入(数据):
用户输入=数据
user_input=user_input.strip();
user\u input=re.sub(“\s{2,},”,user\u input)
inp=用户输入。拆分(“”,1)
cmd=inp[0]
如果cmd==“帮助”:
如果len(inp)==1:
打印“\n可用命令:\n”
对于排序中的c(cmdList):
打印“+c”
返回
## 
##桂
##
def threadit(变量):
thread1=threading.Thread(target=gui\u输入,args=[var])
thread1.start()
类shellGUI(tk.tk):
定义初始化(self,*args,**kwargs):
tk.tk.\uuuuu初始化(self,*args,**kwargs)
tk.tk.title(self,“cmd”)
#mosh应用的主容器
容器=tk.框架(自身)
container.pack(side=“top”,fill=“both”,expand=True)
container.grid_rowconfigure(0,权重=1)
container.grid\u column配置(0,权重=1)
self.frames={}#实例Dict
对于F英寸(起始页,陆地页):
框架=F(容器,自身)
self.frames[F]=帧
frame.grid(行=0,列=0,sticky=“nsew”)
自我显示框架(Landpage)
def显示画面(自身,续):
帧=自身帧[续]
frame.tkraise()
类Landpage(传统框架):
定义初始化(自、父、控制器):
tk.Frame.\uuuu init\uuuuu(自,父)
自我配置(background=“white”)
self.button6=tk.Button(self,text=“Start”,
command=lambda:controller.show_帧(起始页)
,字体=大字体,高=1,宽=13)
self.button6.place(relx=.445,rely=.75)
类起始页(传统框架):
定义初始化(自、父、控制器):
tk.Frame.\uuuu init\uuuuu(自,父)
自我配置(后台=“#cae1ff”)
#记事本
self.nb=ttk.Notebook(self,name='nb',高度=252,宽度=1040,)#在“master”中创建笔记本
self.nb.place(relx=0.005,rely=0.62)#填充“master”,但填充两侧
#命令行选项卡
self.master\u cmd=ttk.Frame(self.nb,name='master-cmd')
self.rx\u textbox=tk.Text(self.master\u cmd,高度=13,
宽度=127,字体=标准(字体)
self.rx_textbox.place(relx=.0,rely=.0)
self.rx\u textbox.tag\u configure(“stderr”,前台=“红色”)
self.rx_textbox.bind(“”,self.takeFocus)
sys.stdout=文本重定向器(self.rx_文本框,“stdout”)
sys.stderr=文本重定向器(self.rx_文本框,“stderr”)
self.cmd\u entrybox=tk.Entry(self.master\u cmd,宽度=127,字体=Norm\u font)
self.contents=tk.StringVar()
self.cmd\u entrybox.config(textvariable=self.contents)
self.cmd\u entrybox.bind(“”,self.Button\u bind)
self.cmd\u entrybox.place(relx=.0,rely=.835)
scrollb=tk.Scrollbar(self.master\u cmd,command=self.rx\u textbox.yview)
scrollb.place(relx=0.985,rely=0.0,height=250)
self.rx_文本框['yscrollcommand']=scrollb.set
self.nb.add(self.master\u cmd,text=“命令行”)
def按钮绑定(自身、事件):
var=self.contents.get()
self.cmd\u entrybox.delete(0,“结束”)
threadit(var)
def takeFocus(自我、事件):
self.cmd\u entrybox.focus()
类TextRedirector(对象):
定义初始化(self,widget,tag=“stdout”):
self.widget=widget
self.tag=tag
def写入(自,strng):
self.widget.configure(state=“normal”)
self.widget.insert(“end”,“”+strng,(self.tag,))
self.widget.configure(state=“disabled”)
self.widget.see(tk.END)
pad=3
app=shellGUI()
app.geometry(“{0}x{1}+0+0”。格式(
app.winfo_屏幕宽度()-pad,app.winfo_屏幕高度()-pad))
应用程序可调整大小(宽度=假,高度=假)
打印“\n在下面输入命令。\r\n键入“帮助”以获取命令列表,键入“退出”以离开”
app.mainloop()

请提供一个,这样我们就可以运行您的代码并查看出了什么问题。首先,您不调用框架的
\uuuu init\uuu
函数。还有,什么是
tk.frame
tk
包括一个
Frame
但不是
Frame
@BryanOakley您好,谢谢您的帮助。我在上面制作了一个可测试的版本,您可以从多个线程访问Tkinter小部件。这根本不能可靠地工作。@jasonharper我执行线程的原因是我有很多命令(函数),它们以一定的延迟将数据包发送到串行线,当我使用相同的GUI线程执行这些命令时,GUI立即崩溃。你怎么看?
import Tkinter as tk
import ttk
import sys
import re
import threading

Large_Font= ("Verdana", 12)
Norm_Font= ("Verdana", 10)
Small_Font=("Verdana", 8)




cmdList = ["command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1",
           "command1"]

def gui_Input(Data) :
   user_input = Data
   user_input = user_input.strip();   
   user_input = re.sub("\s{2,}" , " ", user_input)    
   inp = user_input.split(' ', 1)
   cmd = inp[0]

   if cmd == 'help' :
      if len(inp) == 1 :
         print "\navailable commands:\n"
         for c in sorted(cmdList) :
            print "        " + c
  return

## 
## GUI
##
def threadit(var):
    thread1 = threading.Thread(target = gui_Input, args =[var]) 
    thread1.start()

class shellGUI(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.title(self, "cmd")

        # Main Container of mosh application
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {} # instances Dict

        for F in (Startpage, Landpage):

            frame = F(container,self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(Landpage)


    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()


class Landpage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.configure(background="white")

        self.button6 = tk.Button(self, text="Start", 
                            command= lambda: controller.show_frame(Startpage)
                            ,font= Large_Font,  height = 1, width = 13)

        self.button6.place(relx=.445, rely=.75)           


class Startpage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        self.configure(background="#cae1ff")

        # NoteBook
        self.nb = ttk.Notebook(self, name='nb',height=252, width=1040,) # create Notebook in "master"
        self.nb.place(relx=.005, rely=.62) # fill "master" but pad sides

        # Command Line Tab
        self.master_cmd = ttk.Frame(self.nb, name='master-cmd') 


        self.rx_textbox = tk.Text(self.master_cmd, height=13, 
                                  width=127,font=Norm_Font)
        self.rx_textbox.place(relx=.0, rely=.0)   

        self.rx_textbox.tag_configure("stderr", foreground="red")
        self.rx_textbox.bind('<ButtonRelease-1>', self.takeFocus)

        sys.stdout = TextRedirector(self.rx_textbox, "stdout")
        sys.stderr = TextRedirector(self.rx_textbox, "stderr")


        self.cmd_entrybox = tk.Entry(self.master_cmd, width=127, font=Norm_Font) 
        self.contents = tk.StringVar()

        self.cmd_entrybox.config(textvariable=self.contents)


        self.cmd_entrybox.bind('<Key-Return>', self.Button_Bind)

        self.cmd_entrybox.place(relx=.0, rely=.835)


        scrollb = tk.Scrollbar(self.master_cmd ,command=self.rx_textbox.yview)
        scrollb.place(relx =.985 , rely=.0, height = 250)
        self.rx_textbox['yscrollcommand'] = scrollb.set

        self.nb.add(self.master_cmd, text="Command Line     ")

    def Button_Bind(self,event):
        var =  self.contents.get()
        self.cmd_entrybox.delete(0, "end")
        threadit(var)

    def takeFocus(self,event):
        self.cmd_entrybox.focus()

class TextRedirector(object):
    def __init__(self, widget, tag="stdout"):
        self.widget = widget
        self.tag = tag

    def write(self, strng):

        self.widget.configure(state="normal")
        self.widget.insert("end",' '+ strng, (self.tag,))
        self.widget.configure(state="disabled")
        self.widget.see(tk.END)


pad=3  

app= shellGUI()

app.geometry("{0}x{1}+0+0".format(
            app.winfo_screenwidth()-pad, app.winfo_screenheight()-pad))

app.resizable(width=False, height=False)
print '\nEnter your commands below.\r\nType "help" for a list of commands, type "exit" to leave'

app.mainloop()