I have a pretty strange use-case here, I am trying to put together a handful of simple programs for my students that will help them learn python. To get it working I have a PyGame window embedded in a TKinter frame, and I need to redirect stdout to change something in the PyGame window. I have the redirecting working, if I redirect it to a file it works fine, but if I try to change the text it doesn't work. I hard-coded a string into the PyGame text changing code and that works, but it won't work with the redirected text for some reason.
The redirecting class:
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
the game class:
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()
and I set up the stdout like this:
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()
When I run this as it is, if I type hello in the box, hello is printed to the file, but a null character is put into the pygame box. I don't really know PyGame well enough to know if it is an issue on that end or a redirecting issue. Any help would be greatly appreciated!
(In case you are wondering what the use-case is here, I am going to have them 'finish' some programs to make something happen in PyGame. So if they type print('Hello Friend!') into the given field, it will redirect that to be dialog for someone in the PyGame box. It may not work in the long run, but I gotta get past this to really figure that out)
Edit:
So the problem is that the write function is being called twice for some reason when I click the button, it is calling print on the typed in string then again on an empty string. Still not sure how to fix it, but at least I found the problem
To flip the image we need to use pygame. transform. flip(Surface, xbool, ybool) method which is called to flip the image in vertical direction or horizontal direction according to our needs.
Okay, so I found the problem.
It looks as though print sends two things to stdout, the string to print and the ending character. So it was overwriting the string I wanted printed with a newline character. I changed my PrintTest class to accommodate for this:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With