Pyglet控制器__init__阶段绑定事件监听器触发运行时错误
报错根因
类定义阶段的代码会在类加载时立即执行,此时ActiveController.controller_obj还是初始赋值的None,你在这个阶段用@controller_obj.event绑定回调,本质是对None调用event属性,必然抛出AttributeError。
Pyglet的输入事件装饰器只能作用在已经完成初始化、调用过open()方法的有效控制器实例上,无法提前在类定义阶段绑定动态传入的实例对象。
修复方案
把事件绑定逻辑从类定义阶段移到__init__实例化流程里,等控制器实例传入、完成open()激活后再注册回调,两种常用写法如下:
import pyglet class CursorControl: class ActiveController: # 类定义阶段仅做属性声明,不执行任何实例相关的绑定操作 controller_obj = None def __init__(self, controller_instance): # 1. 接收传入的控制器实例,调用open()激活 self.controller_obj = controller_instance self.controller_obj.open() # 写法1:直接在初始化流程内用装饰器绑定简单回调 @self.controller_obj.event def on_button_press(button_name): print(f"检测到按钮按下: {button_name}") # 写法2:如果回调需要访问实例属性/方法,用push_handlers注册 # 注册后Pyglet会自动匹配类内和事件同名的方法作为回调 self.controller_obj.push_handlers(self) # 和事件同名的实例方法会被自动绑定 def on_button_release(self, button_name): print(f"检测到按钮松开: {button_name},当前实例属性可正常访问") if __name__ == "__main__": # 获取已连接的控制器列表 controller_list = pyglet.input.get_controllers() if not controller_list: print("未检测到可用游戏控制器") exit() # 实例化测试 control = CursorControl.ActiveController(controller_list[0]) pyglet.app.run()
注意事项
- 所有和动态传入实例相关的逻辑,都不要写在类定义的顶层代码块里,这类代码只会在类第一次加载时执行一次,拿不到实例化阶段才传入的参数
- 用
push_handlers注册的回调,如果后续需要解绑,可以保存注册时返回的句柄,调用remove_handlers方法完成解绑 - 必须在控制器调用
open()方法之后再绑定事件,未激活的控制器实例不会触发任何输入回调
内容的提问来源于stack exchange,提问作者Pogmog
相关产品推荐
相关产品推荐

