Tkinter文本框无输出问题求助
问题描述
我尝试将原本输出到控制台的内容改为写入自定义的Tkinter文本框,这些内容来自process_input函数的match-case分支。但目前遇到问题:控制台和文本框均无任何输出,且未抛出任何错误。以下是我编写的代码:
from tkinter import * import sys import time import multiprocessing class Window: def __init__(self, WIDTH, HEIGHT, WIN) -> None: """ Parameters ---------- self.width : int The width of the window created. self.height : int The height of the window created. self.window : tk.TK The window object. Variables --------- self.data : dict A dictonary containing all information about buttons creates and titles displayed on screen. """ self.width = WIDTH self.height = HEIGHT self.window = WIN self.data : dict = { "Title" : None, "btns" : {} } def constract(self, title : str, background_color : str) -> None: """ Creates the main window adds a title and a background color. Parameters ---------- title : str A string which will serve as the window's title. backgound_color : str A string represents a hex code color (e.g. #FFFFFF). """ self.window.title(title) self.window.geometry(f'{self.width}x{self.height}') self.window.configure(bg=background_color) def header(self, text : str, fill : str = "black", font : str = 'Arial 28 bold', background : str ='#E1DCDC') -> None: """ Displays a title on the screen. Parametes --------- text : str The text which will be displayed on the screen. fill : str The color of the text, can be an existing color in tkinter or a custom hex code color (e.g. #FFFFFF). font : str The font type, the size of the letters and other designs for the text. backgound : str The color of the box around the text, can be an existing color in tkinter or a custom hex code color (e.g. #FFFFFF). """ T = Label(self.window, text=text, bg=background ,fg=fill, font=font) T.pack() self.data["Title"] = text def logger(self, BG_color : str, state : bool = False, side ='BOTTOM', anchor='se', area : tuple = ()) -> object: # anchors - n s e w ne nw se sw center # state - TOP BOTTOM LEFT RIGHT if not area: t = Text(self.window, bg=BG_color,bd=1, width=self.width//50, height=self.height//40) else: t = Text(self.window, bg=BG_color,bd=1, width=area[0], height=area[1]) # if not state: # t.config(state=DISABLED) match side: case 'TOP': t.pack(side=TOP, anchor=anchor) case 'BOTTOM': t.pack(side=BOTTOM, anchor=anchor) case 'LEFT': t.pack(side=LEFT, anchor=anchor) case 'RIGHT': t.pack(side=RIGHT, anchor=anchor) case _: raise(ValueError("Value should be a string and one of those: \"LEFT\", \"RIGHT\" \"TOP\", \"BOTTOM\".")) return t class PrintLogger: def __init__(self, textbox): self.textbox = textbox def write(self, text): self.textbox.config(state='normal') self.textbox.insert(END, text) self.textbox.config(state='disabled') def flush(self): pass def Move(direction, q): match direction: case 'left': q.enqueue('left') case 'right': q.enqueue('right') def get_input(seconds, q): win = Tk() WIDTH, HEIGHT = win.winfo_screenwidth(), win.winfo_screenheight() main_window = Window(WIDTH, HEIGHT, win) main_window.constract("AntiBalloons system controls", "#E1DCDC") main_window.header("AntiAir system controls") l = main_window.logger(BG_color='#E1DCDC') sys.stdout = PrintLogger(l) # pass the Text widget to PrintLogger while True: try: win.bind('<A>', lambda event: Move('left', q)) win.bind('<a>', lambda event: Move('left', q)) win.bind('<D>', lambda event: Move('right', q)) win.bind('<d>', lambda event: Move('right', q)) except Exception: print('err') break #main_window.window.after(100, stdout_not_moving) main_window.window.mainloop() time.sleep(seconds) def process_input(seconds, q): while True: if not q.is_empty(): command = q.dequeue() match command: case 'left': sys.stdout.write('Moving left') case 'right': sys.stdout.write('Moving right') else: sys.stdout.write('Not moving') time.sleep(seconds) # def stdout_not_moving(): # print('Not moving') if __name__ == '__main__': multiprocessing.freeze_support() manager = multiprocessing.Manager() q = manager.Queue() p1 = multiprocessing.Process(target=get_input, args=[0.1, q]) p2 = multiprocessing.Process(target=process_input, args=[0.03015, q]) p1.start() p2.start() p1.join() p2.join()
问题分析与修复方案
1. 多进程sys.stdout重定向无效
每个进程的sys.stdout是独立的,get_input进程里的重定向对process_input进程完全不起作用,这是输出无响应的核心原因。
- 修复:新增一个专门传递输出消息的队列
output_q,process_input把要输出的内容放入队列,get_input进程负责从队列取消息并写入文本框。
2. get_input函数逻辑错误
mainloop()是阻塞的事件循环,一旦调用就会持续运行,外层的while True循环和time.sleep永远不会执行;同时按键绑定代码放在循环里完全多余,绑定一次即可。
- 修复:移除外层
while True,将按键绑定代码移到mainloop之前,通过Tkinter的after方法定时更新文本框内容。
3. 多进程队列方法错误
多进程队列没有is_empty()、enqueue()、dequeue()方法,正确的方法是empty()、put()、get()。
- 修复:替换所有错误的队列方法调用。
4. 文本框体验优化
原代码写入的内容没有换行,会堆积在一起;同时需要自动滚动到最新内容。
- 修复:每次写入消息后添加换行符,调用
see(END)滚动到文本框底部。
修复后的完整代码
from tkinter import * import time import multiprocessing class Window: def __init__(self, WIDTH, HEIGHT, WIN) -> None: self.width = WIDTH self.height = HEIGHT self.window = WIN self.data : dict = { "Title" : None, "btns" : {} } def constract(self, title : str, background_color : str) -> None: self.window.title(title) self.window.geometry(f'{self.width}x{self.height}') self.window.configure(bg=background_color) def header(self, text : str, fill : str = "black", font : str = 'Arial 28 bold', background : str ='#E1DCDC') -> None: T = Label(self.window, text=text, bg=background ,fg=fill, font=font) T.pack() self.data["Title"] = text def logger(self, BG_color : str, state : bool = False, side ='BOTTOM', anchor='se', area : tuple = ()) -> object: if not area: t = Text(self.window, bg=BG_color,bd=1, width=self.width//50, height=self.height//40) else: t = Text(self.window, bg=BG_color,bd=1, width=area[0], height=area[1]) match side: case 'TOP': t.pack(side=TOP, anchor=anchor) case 'BOTTOM': t.pack(side=BOTTOM, anchor=anchor) case 'LEFT': t.pack(side=LEFT, anchor=anchor) case 'RIGHT': t.pack(side=RIGHT, anchor=anchor) case _: raise(ValueError("Value should be a string and one of those: \"LEFT\", \"RIGHT\" \"TOP\", \"BOTTOM\".")) return t def Move(direction, q): match direction: case 'left': q.put('left') case 'right': q.put('right') def get_input(output_q, cmd_q): win = Tk() WIDTH, HEIGHT = win.winfo_screenwidth(), win.winfo_screenheight() main_window = Window(WIDTH, HEIGHT, win) main_window.constract("AntiBalloons system controls", "#E1DCDC") main_window.header("AntiAir system controls") log_text = main_window.logger(BG_color='#E1DCDC') # 定时从输出队列获取消息并更新文本框 def update_log(): while not output_q.empty(): msg = output_q.get() log_text.config(state='normal') log_text.insert(END, msg + '\n') log_text.config(state='disabled') log_text.see(END) # 自动滚动到最新内容 win.after(100, update_log) # 绑定按键事件 win.bind('<A>', lambda event: Move('left', cmd_q)) win.bind('<a>', lambda event: Move('left', cmd_q)) win.bind('<D>', lambda event: Move('right', cmd_q)) win.bind('<d>', lambda event: Move('right', cmd_q)) update_log() win.mainloop() def process_input(seconds, cmd_q, output_q): while True: if not cmd_q.empty(): command = cmd_q.get() match command: case 'left': output_q.put('Moving left') case 'right': output_q.put('Moving right') else: output_q.put('Not moving') time.sleep(seconds) if __name__ == '__main__': multiprocessing.freeze_support() manager = multiprocessing.Manager() cmd_q = manager.Queue() output_q = manager.Queue() p1 = multiprocessing.Process(target=get_input, args=[output_q, cmd_q]) p2 = multiprocessing.Process(target=process_input, args=[0.5, cmd_q, output_q]) p1.start() p2.start() p1.join() p2.join()
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

