python-3.x 未显示输出到Tkinter文本框

pcww981p  于 2023-03-31  发布在  Python
关注(0)|答案(1)|浏览(137)

我试图记录一些输出,而不是输出到控制台,我希望它写在一个文本框,我已经定义。
输出应该在proccess_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()
o0lyfsai

o0lyfsai1#

如果我的第一个评论冒犯了你,我想向你道歉。我只是想确定这真的是你写的代码
我只是在解决你不能在文本窗口部件中看到任何东西的事实。还有其他的事情可以改进,但这将超出我的时间和这个问题。
但最突出的是,您在while循环中一遍又一遍地重新启动mainloop(并重新绑定键)。
所以这是不需要的:

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)

试试这个:

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))
    main_window.window.mainloop()

为了测试控制台窗口,我在Move()函数中添加了一些print语句

def Move(direction, q):
    print(f'called from bind, direction: {direction}\n')
    match direction:
        case 'left':
            print('moving left\n')
            q.enqueue('left')
        case 'right':
            print('moving right\n')
            q.enqueue('right')

我将logger()的返回改为tkinter.Text而不是object。

def logger(self, bg_color: str, state: bool = False, side='BOTTOM', anchor=tkinter.SE, area: tuple = ()) -> tkinter.Text:

请检查您的代码的更新版本。您应该在文本框中看到控制台输出。

import tkinter
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=tkinter.SE, area: tuple = ()) -> tkinter.Text:
        # 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):
    print(f'called from bind, direction: {direction}\n')
    match direction:
        case 'left':
            print('moving left\n')
            q.enqueue('left')
        case 'right':
            print('moving right\n')
            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')
    l.insert(tkinter.END, 'test text')

    sys.stdout = PrintLogger(l)  # pass the Text widget to PrintLogger

    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))
    # main_window.window.after(100, stdout_not_moving)
    main_window.window.mainloop()

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():

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()

我想知道,为什么你首先使用多处理?我所做的所有更改都不会解决多任务问题。你能摆脱多处理吗?还是其他地方需要它?

相关问题