如何在Pygame中为按钮绑定带参数的函数?
Pygame按钮绑定带参数函数触发TypeError的解决方法
问题原因
你在初始化Button时写了sample(s),这会立即执行sample函数,而sample没有返回值(默认返回None),导致Button实例的onclick_function被赋值为None。当按钮被点击时,代码尝试调用这个None对象,就会抛出TypeError: 'NoneType' object is not callable错误。
解决方案
方案1:用Lambda表达式包装带参数函数
修改Button初始化代码,用lambda将带参数的函数包装成无参可调用对象,只有点击时才会执行目标函数:
btn = Button('Button', 200, 50, 300, 250, lambda: sample(s))
方案2:修改Button类支持传递函数参数
如果需要更灵活地处理多参数函数,可以扩展Button类,增加接收函数参数的属性:
import pygame import sys pygame.init() W, H = 800, 600 display = pygame.display.set_mode((W, H)) font1 = pygame.font.SysFont('Arial', 40) clock = pygame.time.Clock() fps = 30 class Button: def __init__(self, button_text, width, height, x, y, onclick_function=None, onclick_args=None, one_press=False): self.button_text = button_text self.x = x self.y = y self.width = width self.height = height self.onclick_function = onclick_function # 处理函数参数,默认空列表 self.onclick_args = onclick_args if onclick_args is not None else [] self.one_press = one_press self.already_pressed = False self.fillColors = { 'normal': '#ffffff', 'hover': '#666666', 'pressed': '#333333', } self.button_surface = pygame.Surface((self.width, self.height)) self.button_rect = pygame.Rect(self.x, self.y, self.width, self.height) self.button_surf = font1.render(button_text, True, (20, 20, 20)) def draw(self): mouse_pos = pygame.mouse.get_pos() self.button_surface.fill(self.fillColors['normal']) if self.button_rect.collidepoint(mouse_pos): self.button_surface.fill(self.fillColors['hover']) if pygame.mouse.get_pressed(num_buttons=3)[0]: self.button_surface.fill(self.fillColors['pressed']) # 先判断函数是否存在再调用 if self.onclick_function is not None: if self.one_press: self.onclick_function(*self.onclick_args) elif not self.already_pressed: self.onclick_function(*self.onclick_args) self.already_pressed = True else: self.already_pressed = False self.button_surface.blit(self.button_surf, [ self.button_rect.width / 2 - self.button_surf.get_rect().width / 2, self.button_rect.height / 2 - self.button_surf.get_rect().height / 2 ]) display.blit(self.button_surface, self.button_rect) def sample(g): print(g) s = 15 # 传递函数和对应的参数列表 btn = Button('Button', 200, 50, 300, 250, sample, [s]) while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() display.fill('blue') btn.draw() pygame.display.update() clock.tick(fps)
这种方式支持传递任意数量的参数,比如目标函数是sample(a, b, c),就传onclick_args=[a, b, c]。
方案3:使用functools.partial绑定参数
通过functools.partial创建一个预先绑定参数的可调用对象:
import pygame import sys import functools pygame.init() # 其余初始化代码不变... def sample(g): print(g) s = 15 # 用partial绑定参数 btn = Button('Button', 200, 50, 300, 250, functools.partial(sample, s))
partial会返回一个新的可调用对象,点击按钮时会自动以绑定的参数执行目标函数。
内容的提问来源于stack exchange,提问作者SklerosisTim
相关产品推荐
相关产品推荐

