Botón de comandos en Tkinter

Estoy tratando de hacer una aventura de texto con tkinter y poco a poco estoy juntando algo. Intento mostrar los comandos a medida que van de una habitación a otra, pero aunque aparecen los botones, no sucede nada cuando los presiono.

game.py

 #!/usr/bin/python # -*- coding: utf-8 -*- import world from player import Player from ui import * def main(): gui = Window(root()) while True: gui.mainloop() else: pass if __name__ == '__main__': main() 

ui.py

 #!/usr/bin/python # -*- coding: utf-8 -*- import tkinter as tk from tkinter import ttk import world, tiles, action from player import Player class Window(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master=master) self.master = master self.player = Player() self.init_ui() def init_ui(self): self.master.title("****") self.tabs = Tabs(self.master) world.load_tiles() self.world = world.tile_exists(self.player.location_x, self.player.location_y) self.update_main() def update_main(self): self.world.scene_init() self.world.modify_player(self.player) self.tabs.update_tab(self.world, self.player) def _label(self, master, text, side=None, anchor=None): new_label = tk.Label(master, text=text) new_label.pack(side=side, anchor=anchor) def _button(self, master, text, command, side=None, anchor=None): new_button = tk.Button(master, text=text, command=command) new_button.pack(side=side, anchor=anchor) class Tabs(Window): def __init__(self, master): self.master = master self.nb = ttk.Notebook(self.master) nb_1 = ttk.Frame(self.nb) self.frame_1 = tk.Frame(nb_1, bg='red', bd=2, relief=tk.SUNKEN, padx=5, pady=5) self.frame_1.pack(expand=1, fill='both', side=tk.LEFT) self.nb.add(nb_1, text='Game') self.nb.pack(expand=1, fill='both', side=tk.LEFT) def update_tab(self, world, player): avaliable_actions = world.avaliable_actions() self._label(self.frame_1, world.display_text(), side=tk.LEFT, anchor=tk.N) for action in avaliable_actions: self._button(self.frame_1, text=action, command=player.do_action(action, **action.kwargs), side=tk.BOTTOM, anchor=tk.E) def root(): root = tk.Tk() root.geometry("600x350+200+200") return root 

world.py

 #!/usr/bin/python # -*- coding: utf-8 -*- _world = {} def tile_exists(x, y): """Returns the tile at the given coordinates or None if there is no tile. :param x: the x-coordinate in the worldspace :param y: the y-coordinate in the worldspace :return: the tile at the given coordinates or None if there is no tile """ return _world.get((x, y)) def load_tiles(): with open('scenes.txt', 'r') as f: rows = f.readlines() x_max = len(rows[0].split('\t')) for y in range(len(rows)): cols = rows[y].split('\t') for x in range(x_max): tile_name = cols[x].replace('\n', '') _world[(x, y)] = None if tile_name == '' else getattr(__import__('tiles'), tile_name)(x, y) return _world 

tiles.py

 #!/usr/bin/python # -*- coding: utf-8 -*- import world, action from player import Player class MapTile(): def __init__(self, x, y): self.x = x self.y = y def display_text(self): pass # raise NotImplementedError() def modify_player(self, the_player): raise NotImplementedError() def adjacent_moves(self): moves = [] if world.tile_exists(self.x + 1, self.y): moves.append(action.MoveEast()) if world.tile_exists(self.x - 1, self.y): moves.append(action.MoveWest()) if world.tile_exists(self.x, self.y - 1): moves.append(action.MoveNorth()) if world.tile_exists(self.x, self.y + 1): moves.append(action.MoveSouth()) return moves def avaliable_actions(self): '''Returns all of the default avaliable_actions in a room''' moves = self.adjacent_moves() # moves.append(action.ViewInventory()) return moves class Scene_1(MapTile): def scene_init(self): self.location = 'Scene_1' self.long_desc = 'Welcome to {}, the shittiest place on earth.'.format(self.location) self.short_desc = 'Eh, I don\'t care.' def display_text(self): return self.long_desc def modify_player(self, the_player): self.first = True return self.display_text() class Scene_2(MapTile): def scene_init(self): self.location = 'Scene_2' self.long_desc = 'This is {}, but noone gives a damn.'.format(self.location) self.short_desc = 'Eh, I don\'t care, really.' def display_text(self): return self.long_desc def modify_player(self, the_player): self.first = True return self.display_text() 

player.py

 #!/usr/bin/python # -*- coding: utf-8 -*- class Player(): '''Base for player''' def __init__(self): self.inventory = [] self.hp = 100 self.location_x, self.location_y = 1, 1 self.victory = False def is_alive(self): return self.hp >= 0 def do_action(self, action, **kwargs): action_method = getattr(self, action.method.__name__) if action_method: action_method(**kwargs) def print_inventory(self): for item in self.inventory: print(item, 'n') def move(self, dx, dy): self.location_x += dx self.location_y += dy def move_north(self): self.move(dx=0, dy=-1) def move_south(self): self.move(dx=0, dy=1) def move_east(self): self.move(dx=1, dy=0) def move_west(self): self.move(dx=-1, dy=0) 

action.py

 #!/usr/bin/python # -*- coding: utf-8 -*- from player import Player class Action(): def __init__(self, method, name, **kwargs): """Creates a new action :param method: the function object to execute :param name: the name of the action :param ends_turn: True if the player is expected to move after this action else False :param hotkey: The keyboard key the player should use to initiate this action """ self.method = method self.name = name self.kwargs = kwargs def __str__(self): return "{}".format(self.name) class MoveNorth(Action): def __init__(self): super().__init__(method=Player.move_north, name='north') class MoveSouth(Action): def __init__(self): super().__init__(method=Player.move_south, name='south') class MoveEast(Action): def __init__(self): super().__init__(method=Player.move_east, name='east') class MoveWest(Action): def __init__(self): super().__init__(method=Player.move_west, name='west') class ViewInventory(Action): """Prints the player's inventory""" def __init__(self): super().__init__(method=Player.print_inventory, name='View inventory', hotkey='i') class Attack(Action): def __init__(self, enemy): super().__init__(method=Player.attack, name="Attack", hotkey='a', enemy=enemy) class Flee(Action): def __init__(self, tile): super().__init__(method=Player.flee, name="Flee", hotkey='f', tile=tile) 

command espera el nombre de la función sin () y argumentos.

Error:

 command=player.do_action(action, **action.kwargs) 

De esta manera, asigna un valor de command devuelto por player.do_action() pero esta función devuelve None

Tienes que usar la función lambda

 command=lambda:player.do_action(action, **action.kwargs) 

pero quizás también necesite argumentos en lambda porque crea esto en el bucle for .

 command=lambda act=action, kws=action.kwargs : player.do_action(act, **kws)