from tkinter import Tk, Text, END from tkinter.font import Font class Game: def __init__(self, width=80, height=24, title="Untitled", active_keys=None): self._root = Tk() self._root.resizable(False, False) self._root.title(title) if active_keys is None: active_keys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '', '', '', ''] for key in active_keys: self._root.bind(key, self._render) self.width = width self.height = height self._text = Text( self._root, width=self.width, height=self.height, bg='black', fg='white', ) self._text.insert('1.0', ' ' * (self.width * self.height)) self._text.pack() self._text['state'] = 'disabled' def _render(self, event): self._text['state'] = 'normal' self._text.delete('1.0', END) content = self.loop(event) if len(content) == self.width * self.height: self._text.insert('1.0', content) else: raise ValueError("Game.loop(event) must return a string of " "length {}x{}".format(self.width, self.height)) self._text.pack() self._text['state'] = 'disabled' def loop(self, event): raise NotImplementedError("Subclass must implement Game.loop(event).") def run(self): self._root.mainloop() # # Usage example: # import random # import string # from functools import reduce # # class Rogue(Game): # def loop(self, event): # if event.keysym == 'Left': # return 24 * 80 * '<' # return ''.join([random.choice(string.ascii_letters) # for _ in range(24 * 80)]) # # Rogue().run()