首页 > 解决方案 > 我在 Pygame 中创建了一个 Toggle Box 类,但它没有修改我作为参数传递给它的原始布尔值

问题描述

我正在开发一个简单的 Pygame 项目,在选项菜单中,我有几个用于关闭声音和动画的切换框。这些的布尔变量存储在单独的设置类中。

虽然这不是真的必要,但我想我会尝试制作一个 ToggleButton 类,它采用以下参数:

ToggleButton(game_instance, boolean, text, xpos, ypos, width, height)

我给了它一个draw()方法和一个toggle()方法。我想从我的主游戏程序中传递我的self.settings.sounds_onself.settings.animations_on布尔值,以便打开和关闭切换框将打开和关闭声音和动画。

在对此进行测试时,我创建了 ToggleButton 类的两个实例:

ToggleButton(self, self.game_instance, self.settings.sounds_on, "Sounds", 50, 100, 25, 25)
ToggleButton(self, self.game_instance, self.settings.animations_on, "Animations", 50, 150, 25, 25)

切换框绘制屏幕,​​并且可以与之交互。

屏幕上切换框的图像

然而,虽然toggle()方法改变了类实例中的布尔值,但它似乎并没有连接到作为参数传递给实例的原始布尔值(我希望我使用的是这里的术语正确,我还在学习)。因此,虽然切换框的外观会根据布尔值是 True 还是 False 而发生变化,但它实际上对声音和动画的设置根本没有任何影响。

这是按钮代码的链接,也是一个简短的示例程序,它只在屏幕上绘制一个切换框,每次单击它时,它都会打印原始布尔值的状态,以及实例内的布尔值。您可以清楚地看到原始布尔值始终为 False,而切换框的self.boolean参数发生了变化。

https://github.com/ElJuanito82/ToggleBox/blob/main/example

因此,似乎在实例化按钮时,它会获取当前状态下的布尔值的副本,而不是创建直接链接,以便在一个更改时另一个更改。我在这里有正确的想法吗?

我在这里缺少什么可以使它起作用的东西吗?

标签: pythonclassoopboolean

解决方案


布尔参数是按值传递的,不能以这种方式修改它。最好的解释可能是这个问答集 -如何通过引用传递变量?. 相当多的“教程”在细节上是不正确的,甚至说“一切都是通过引用传递的”——这是错误的。通常基本类型是按值传递的——布尔值、数字、元组、字符串。对象和列表之类的大多数其他内容都是通过引用传递的——这意味着可以在函数中更改这些内容。

考虑这个 python 会话:

Python 3.8.5 (default, Jul 28 2020, 12:59:40) 
>>> x = True
>>> def f( boolval ):
...     boolval = False
... 
>>> f(x)
>>> x
True  # <-- Still the original value

x不会更改,因为它是作为值传递的。现在考虑同样的事情,但使用列表参数:

>>> y = [ 'apple', 'banana', 'cherry' ]
>>> def f2( fruit_list ):
...     fruit_list.append( 'durian' )
... 
>>> f2( y )
>>> y
['apple', 'banana', 'cherry', 'durian']   # <-- Changed!

这里传递了一个列表作为引用,因此可以在函数中对其进行修改。如果您打算像这样进行编码,重要的是要知道哪些类型是可变的,哪些不是。

因此,对于您的ToggleButton,显然现在我们知道布尔参数是不可变的,因此不会被更改。但是您可以并且确实更改对象内部的值。所以添加辅助函数来设置和查询它。

这是在面向对象的 GUI 控件中实现此类功能的常用方法,而不是直接询问成员变量。

例如:

class ToggleButton:

    def __init__(self, game_instance, boolean, text, xpos, ypos, width, height):
        """Initialise the toggle box attributes."""
        self.game_instance = game_instance
        self.boolean = boolean
        # [...]

    def isToggled( self ):
        """ Return True if the toggle is selected """
        return self.boolean

    def setToggled( self, value ):
        """ Set the state of the Toggle """
        self.boolean = value
        ### TODO: cause a re-draw, iff necessary

撇开:boolean不是一个变量的好名字,因为它不是描述性的。类似 , 或 的东西.is_set可能.checked.selected更好,因为它描述了内容所代表的内容。


推荐阅读