【问题标题】:Redirecting stdout in Python into PyGame将 Python 中的标准输出重定向到 PyGame
【发布时间】:2020-12-08 05:35:42
【问题描述】:

我在这里有一个非常奇怪的用例,我正在尝试为我的学生编写一些简单的程序来帮助他们学习 python。为了让它工作,我在 TKinter 框架中嵌入了一个 PyGame 窗口,我需要重定向 stdout 以更改 PyGame 窗口中的某些内容。我有重定向工作,如果我将它重定向到一个文件它工作正常,但如果我尝试更改文本它不起作用。我将一个字符串硬编码到 PyGame 文本更改代码中,并且可以正常工作,但由于某种原因,它不适用于重定向的文本。

重定向类:

class PrintTest:
    def __init__(self, file, game):
        self.f = file
        self.game = game
    
    def write(self, t):
        f.write(t)

        self.game.text = game.font.render(t, True, self.game.text_colors[1], self.game.text_colors[2])
        self.game.textRect = self.game.text.get_rect()

        self.game.textRect.center = (300, 300)

    def flush(self):
        pass

游戏类:

class Game:
    def __init__(self, root):
        self.root = root
        embed = tk.Frame(root, width=600, height=600)
        embed.pack(side=tk.LEFT)

        os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
        if platform.system == "Windows":
            os.environ['SDL_VIDEODRIVER'] = 'windib'

        self.text_colors = [(255,255,255),
                            (0,255,0),
                            (0,0,128)]

        # initialize a pygame display
        pygame.init()
        self.screen = pygame.display.set_mode((600, 600))
        self.screen.fill(pygame.Color('red'))
        self.clock = pygame.time.Clock()

        self.font = pygame.font.Font('freesansbold.ttf', 32)
        self.text = self.font.render('Hello, world!', True, self.text_colors[1], self.text_colors[2])
        self.textRect = self.text.get_rect()

        self.textRect.center = (300, 300)

        # TK Creation
        helv = font.Font(family='Helvetica', size=18, weight='bold')
        self.button = tk.Button(root, 
                                text="Change text",
                                font=helv,
                                command=self.change_text).pack()

        self.user_input = tk.StringVar()
        self.textbox = ttk.Entry(root, width=15, textvariable=self.user_input)
        self.textbox.pack()
        # ---------------------------------------------------------------

    def change_text(self):
        print(self.user_input.get())

    def run(self):
        # Pygame loop
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False

            self.screen.fill(pygame.Color('red'))    

            self.screen.blit(self.text, self.textRect)

            pygame.display.update()

            try:
                self.root.update()
            except tk.TclError:
                running = False   
        pygame.quit()

我这样设置标准输出:

try:
    root = tk.Tk()
    root.geometry('1000x600')

    game = Game(root)

    f = open('text.txt', 'w')
    sl = PrintTest(f, game)
    sys.stdout = sl

    game.run()
except Exception:
    traceback.print_exc()
    pygame.quit()

当我按原样运行时,如果我在框中键入 hello,则会将 hello 打印到文件中,但会在 pygame 框中输入一个空字符。我对 PyGame 的了解还不够深入,无法知道这到底是一个问题还是重定向问题。任何帮助将不胜感激!

(如果你想知道这里的用例是什么,我会让他们“完成”一些程序以在 PyGame 中发生一些事情。所以如果他们在给定的输入中键入 print('Hello Friend!')字段,它将重定向到 PyGame 框中某人的对话框。从长远来看,它可能无法正常工作,但我必须克服这个问题才能真正弄清楚)

编辑:

所以问题是,当我单击按钮时,由于某种原因,write 函数被调用了两次,它在输入的字符串上调用 print,然后在空字符串上再次调用。仍然不知道如何解决它,但至少我找到了问题

【问题讨论】:

  • 我很难理解您的问题。你的标题写着TypeError,你写了一些关于当你“尝试更改它不起作用的文本”,但它确实有效但显示附加了一个空字符(或它只显示空字符吗?)。你遇到的主要问题是什么?如果您有实际的错误消息,请将其包含在问题中。另外,请确保您在问题中的缩进是正确的。
  • 不完全是类型错误,我不应该把它作为标题,这是我遇到的错误,但不是问题所在。问题是传递给我的标准输出替换的字符串在添加到文件时打印正常,但是当我尝试修改 PyGame 字符串时它只打印一个空字符。 typeerror 来自我试图在 printtest 类中打印 t 的类型。缩进很抱歉,这里的文本输入在将代码移入后添加缩进并不是特别好
  • 您是否尝试在def write(self, t) 中打印t?它是否只包含空字符?如果是这样,那么您就知道问题不在于 pygame,而在于重定向。我没有做太多这样的重定向,但我猜t 是一个迭代器,并在f.write(t) 上被消耗
  • 我需要将标准输出重置到控制台才能尝试,这就是我将其推送到文件的原因。该文件显示了正确的文本,所以我相当肯定不是重定向
  • 我也想知道,但即使我删除 f.write(t) 它仍然显示空字符

标签: python pygame stdout


【解决方案1】:

好的,所以我发现了问题。

看起来好像 print 向 stdout 发送了两件事,要打印的字符串和结束字符。所以它用换行符覆盖了我想要打印的字符串。我改变了我的 PrintTest 类来适应这个:

class PrintTest:
    def __init__(self, file, game):
        self.f = file
        self.game = game

    def write(self, t):
        if t != '\n':
            self.f.write(t)
            self.game.text, self.game.textRect = game.font.render(t, self.game.text_colors[2])

            self.game.textRect.center = (300, 300)

    def flush(self):
        pass

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 2014-02-21
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多