Button commands in Tkinter

匿名 (未验证) 提交于 2019-12-03 01:01:02

问题:

I'm trying to make a text adventure with tkinter and I'm slowly getting something together. I'm trying to display commands as they come from room to room but even though the buttons appear, nothing happens when I press them.

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) 

回答1:

command expect function name without () and arguments.

Mistake:

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

This way you assign to command value returned by player.do_action() but this functions returns None

You have to use lambda function

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

but maybe you will need also arguments in lambda because you create this in for loop.

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!