如何在discord.py中使带custom_id的按钮正常响应点击?
问题分析与修复方案
核心问题点
- 你搞混了
interaction.id和按钮的custom_id:interaction.id是每次点击生成的唯一交互ID,每次点都会变;要获取按钮设置的自定义ID,得用interaction.component.custom_id或者interaction.data["custom_id"]。 - 所有按钮的
custom_id都设成了同一个值"Filou",根本没法区分不同玩家的按钮。 - 回调函数绑定位置错了:循环里创建的按钮只有最后一个会被绑定
filou回调,前面的按钮都没关联上响应逻辑。 - 自定义的
Report_Buttons没继承discord.ui.View,这样的视图根本没法正常工作。
修正后的代码
from discord import ButtonStyle, Interaction from discord.ui import View, Button # 先定义正确的视图类 class Report_Buttons(View): def __init__(self, ctx): super().__init__(timeout=None) # 设置timeout=None让视图持久化,按需调整超时时间 self.ctx = ctx # 举报命令部分 @bot.command() async def Report(ctx): players = list(player_list.values()) view = Report_Buttons(ctx) for player in players: # 给每个按钮生成唯一custom_id,比如用玩家ID做标识 player_unique_id = str(player[0]) # 假设player[0]是玩家的唯一ID,也可以用名字 button = Button( style=ButtonStyle.danger, label=str(player[1]), disabled=False, custom_id=f"report_player_{player_unique_id}" # 每个按钮的ID唯一 ) # 给当前按钮绑定回调逻辑 async def button_callback(interaction: Interaction): # 获取当前按钮的自定义ID current_btn_id = interaction.component.custom_id # 提取玩家ID,判断是哪个玩家的按钮被点了 if current_btn_id.startswith("report_player_"): target_id = current_btn_id.split("_")[-1] target_player = next(p for p in players if str(p[0]) == target_id) await ctx.send(f"玩家「{target_player[1]}」的按钮被点击了!") button.callback = button_callback view.add_item(button) await ctx.send("请选择要举报的玩家:", view=view)
关键修改说明
- 正确获取按钮ID:用
interaction.component.custom_id拿到你设置的自定义ID,再也不会被每次变化的交互ID搞混。 - 唯一标识按钮:每个按钮的
custom_id带上玩家的唯一信息,确保能精准区分是谁的按钮被点击。 - 循环内绑定回调:在创建每个按钮的同时绑定回调,保证所有按钮都有响应逻辑。
- 规范视图类:让
Report_Buttons继承discord.ui.View,这是Discord按钮视图的基础要求。
如果不想给每个按钮单独写回调,也可以用视图的装饰器批量处理,更简洁:
class Report_Buttons(View): def __init__(self, ctx, players): super().__init__(timeout=None) self.ctx = ctx self.players = players # 匹配所有以report_player_开头的按钮 @discord.ui.button(custom_id="report_player_", style=ButtonStyle.danger) async def handle_player_click(self, interaction: Interaction, button: Button): target_id = button.custom_id.split("_")[-1] target_player = next(p for p in self.players if str(p[0]) == target_id) await self.ctx.send(f"玩家「{target_player[1]}」的按钮被点击了!") @bot.command() async def Report(ctx): players = list(player_list.values()) view = Report_Buttons(ctx, players) for player in players: button = Button( style=ButtonStyle.danger, label=str(player[1]), disabled=False, custom_id=f"report_player_{str(player[0])}" ) view.add_item(button) await ctx.send("请选择要举报的玩家:", view=view)
内容的提问来源于stack exchange,提问作者Miniveleur
相关产品推荐
相关产品推荐

