如何用discord.py实现Discord机器人的按钮式确认提示?
解决Discord机器人命令确认按钮的返回值问题
要实现confirmationPrompt()根据按钮点击返回True/False,核心是利用异步任务结果传递机制(asyncio.Future),因为按钮回调函数无法直接向外层函数返回值。以下是具体实现方案:
方案一:使用View + asyncio.Future(推荐)
这种方式符合discord.py的组件设计规范,代码结构清晰且易扩展:
import asyncio import discord from discord import app_commands async def confirmationPrompt(interaction: discord.Interaction, warning: str, timeout: int = 60) -> bool: class ConfirmationButtons(discord.ui.View): def __init__(self): super().__init__(timeout=timeout) # 初始化Future对象,用于存储按钮点击结果 self.future = asyncio.Future() @discord.ui.button(label='✅', style=discord.ButtonStyle.success) async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): # 限制仅发起命令的用户可操作 if interaction.user != interaction.message.interaction.user: await interaction.response.send_message("只有发起命令的用户可以确认!", ephemeral=True) return # 设置Future结果为True,停止View监听 self.future.set_result(True) await interaction.response.edit_message(content="已确认", embed=None, view=None) self.stop() @discord.ui.button(label='❌', style=discord.ButtonStyle.danger) async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user != interaction.message.interaction.user: await interaction.response.send_message("只有发起命令的用户可以取消!", ephemeral=True) return # 设置Future结果为False,停止View监听 self.future.set_result(False) await interaction.response.edit_message(content="已取消", embed=None, view=None) self.stop() async def on_timeout(self): # 超时自动设置结果为False,并更新消息 self.future.set_result(False) await interaction.edit_original_response(content="确认超时", embed=None, view=None) view = ConfirmationButtons() embed = discord.Embed(title=f"Are you sure you want to {warning}") await interaction.response.send_message(embed=embed, view=view) # 等待Future返回结果,返回给外层函数 result = await view.future return result
关键逻辑说明
- 在
ConfirmationButtons类中初始化asyncio.Future对象,作为结果传递的容器 - 按钮点击时,通过
self.future.set_result()设置对应结果,并调用self.stop()停止View的交互监听 - 实现
on_timeout方法,处理用户未点击的超时场景,自动返回False - 外层函数等待
view.future完成,将结果返回
方案二:使用wait_for监听交互事件
如果不想自定义View,也可以直接监听按钮交互事件,代码更直接但结构较零散:
import asyncio import discord from discord import app_commands async def confirmationPrompt(interaction: discord.Interaction, warning: str, timeout: int = 60) -> bool: embed = discord.Embed(title=f"Are you sure you want to {warning}") # 创建按钮组件 confirm_btn = discord.ui.Button(label='✅', style=discord.ButtonStyle.success) cancel_btn = discord.ui.Button(label='❌', style=discord.ButtonStyle.danger) view = discord.ui.View() view.add_item(confirm_btn) view.add_item(cancel_btn) msg = await interaction.response.send_message(embed=embed, view=view) # 定义交互检查逻辑:仅匹配当前消息和发起命令的用户 def check(btn_interaction: discord.Interaction): return btn_interaction.message.id == msg.id and btn_interaction.user == interaction.user try: # 等待按钮交互事件 btn_interaction = await interaction.client.wait_for('interaction', check=check, timeout=timeout) if btn_interaction.component.label == '✅': await btn_interaction.response.edit_message(content="已确认", embed=None, view=None) return True else: await btn_interaction.response.edit_message(content="已取消", embed=None, view=None) return False except asyncio.TimeoutError: # 超时处理 await interaction.edit_original_response(content="确认超时", embed=None, view=None) return False
两种方案对比
- 方案一(View+Future):更符合discord.py组件设计模式,便于后续扩展(如添加更多按钮、自定义样式),代码可维护性更高
- 方案二(wait_for):代码更简洁直接,但需要手动处理事件监听和检查逻辑,扩展性较差
内容的提问来源于stack exchange,提问作者3LL KNJ
相关产品推荐
相关产品推荐

