python - Tkinter 中的按钮命令

标签 python python-3.x tkinter ttk

我正在尝试使用 tkinter 进行文本冒险,我正在慢慢地把一些东西放在一起。我正在尝试显示从一个房间到另一个房间的命令,但即使按钮出现,当我按下它们时也没有任何反应。

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 期望没有 () 和参数的函数名。

错误:

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

通过这种方式,您可以将 player.do_action() 返回的值分配给 command 但此函数返回 None

你必须使用lambda函数

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

但也许您还需要 lambda 中的参数,因为您在 for 循环中创建了它。

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

关于python - Tkinter 中的按钮命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35078644/

相关文章:

python - 如何设置导入模块的日志级别?

python - 运行时警告 : coroutine 'main' was never awaited

python-3.x - 根据其他列将工作日添加到 pandas df 日期列

Python 导入错误 : cannot import name '_imagingtk' in virtualenv

python - 锯齿 tkinter 主循环帧持续时间?

c++ - 如何使用opencv获取笔划路径?

python - 使用 pyinstaller 打包一个 twistd 插件

python-3.x - 如何从 numpy 数组中输入数据来训练 CNTK 回归模型

python - 使用 Python 匹配新闻数据中的公司名称

python - 如何在 python 中以有理数形式打印/显示表达式