However, I want to create a generic class that can generate an arbitrary number of buttons. I tried this approach:
class MultiButtonView(discord.ui.View):
def __init__(self, buttons):
super().__init__()
self.result = None
for label, value, color in buttons:
self.add_item(self.make_button(label, value, color))
def make_button(self, label, value, color):
async def click(interaction):
self.result = value
await interaction.response.defer()
self.stop()
return discord.ui.Button(label=label, style=color, callback=click)
When I call view = MultiButtonView([('Yes', 'Yes', discord.ButtonStyle.green), ('No', 'No', discord.ButtonStyle.red)]), no buttons appear. What could be the issue and how can I resolve it?
I’ve dealt with similar challenges in my Discord bot projects. The issue you’re facing is likely related to how button callbacks are handled in discord.py.
One approach that worked well for me was using a class method as the callback instead of a closure. Here’s a modified version of your MultiButtonView class that should solve the problem:
class MultiButtonView(discord.ui.View):
def __init__(self, buttons):
super().__init__()
self.result = None
for label, value, color in buttons:
button = discord.ui.Button(label=label, style=color)
button.callback = self.make_callback(value)
self.add_item(button)
def make_callback(self, value):
async def callback(interaction):
self.result = value
await interaction.response.defer()
self.stop()
return callback
This method creates a separate callback function for each button, which should resolve the issue you’re experiencing. Give it a try and see if it works for your use case.
I’ve encountered a similar issue when trying to dynamically generate buttons. The problem likely stems from how Discord.py handles button callbacks. Instead of using a closure, try subclassing discord.ui.Button and overriding its callback method. Here’s a modified version that should work:
class DynamicButton(discord.ui.Button):
def __init__(self, label, value, color):
super().__init__(label=label, style=color)
self.value = value
async def callback(self, interaction):
view = self.view
view.result = self.value
await interaction.response.defer()
view.stop()
class MultiButtonView(discord.ui.View):
def __init__(self, buttons):
super().__init__()
self.result = None
for label, value, color in buttons:
self.add_item(DynamicButton(label, value, color))
This approach should create the buttons as expected and properly handle interactions. Let me know if you need any clarification on this solution.