You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:15:25