Button commands in Tkinter

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-04 06:25:13

问题


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)


来源:https://stackoverflow.com/questions/35078644/button-commands-in-tkinter

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