分类: Discord 机器人开发

Discord 机器人开发#6实现下拉菜单(Select Menu)!

本文译自韩语原文。

目录8 项

大家好!我是 Mojangcam 😎

在上一篇 #5中,我们学习了如何用按钮(Button)和机器人交互,对吧?这次再进一步,来做一个下拉菜单(Select Menu)!

按钮适合只有 2~3 个选项的场景,可一旦选项超过 5 个,屏幕就会被按钮塞满。这时候用下拉菜单,就能把最多 25 个选项整整齐齐地放进一个菜单里。身份组选择、问卷调查、游戏服务器选择菜单等场景都非常常用!

📌 准备工作

  • Python 3.8 及以上
  • discord.py 2.x(Select Menu 从 2.0 开始支持!)
  • 机器人 Token + 已把机器人邀请进服务器(参考本系列第 1 篇!)
终端
pip install -U discord.py

可以用 pip show discord.py 查看版本。2.x 及以上就 OK!1.x 版本无法运行。

📌 第 1 步 - 创建 Select(下拉菜单)类

下拉菜单的核心是 discord.ui.Select 类。继承这个类,然后定义选项(SelectOption)和选择后的行为(callback)。

Python
import discord
from discord.ext import commands

class GameSelect(discord.ui.Select):
    def __init__(self):
        options = [
            discord.SelectOption(label="我的世界", value="minecraft", description="用方块搭建的世界", emoji="⛏️"),
            discord.SelectOption(label="方舟:生存进化", value="ark", description="和恐龙一起求生!", emoji="🦖"),
            discord.SelectOption(label="无畏契约", value="valorant", description="5v5 战术 FPS", emoji="🔫"),
        ]
        super().__init__(
            placeholder="请选择你喜欢的游戏!",
            min_values=1,
            max_values=1,
            options=options,
        )

    async def callback(self, interaction: discord.Interaction):
        await interaction.response.send_message(
            f"🎮 {interaction.user.mention} 选择了 **{self.values[0]}**!"
        )

逐个拆解来看 💡

  • SelectOption:下拉菜单里显示的每一个选项。label 是屏幕上显示的名称,value 是代码中接收到的值,description 是灰色的说明文字,emoji 是显示在前面的表情。
  • placeholder:还没有选择任何内容时显示的提示文字。
  • min_values / max_values:最少·最多可选数量。设置成 max_values=3 就变成多选菜单了!(最多 25)
  • callback:用户完成选择后执行的函数。选中的值会放进 self.values 列表里。

📌 第 2 步 - 放进 View 里

就像在按钮篇中学到的那样,所有 UI 组件都要装进一个叫 View 的容器里再发送。

Python
class GameSelectView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=60)  # 60 秒后失效
        self.add_item(GameSelect())

顺便一提,一个下拉菜单会独占 View 的一整行(row)。View 最多只有 5 行,所以一个 View 里最多只能放 5 个下拉菜单。

📌 第 3 步 - 用斜杠命令发送

Python
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    await bot.tree.sync()
    print(f"✅ {bot.user} 机器人已准备就绪!")

@bot.tree.command(name="게임선택", description="来选一个你喜欢的游戏吧!")
async def game_select(interaction: discord.Interaction):
    await interaction.response.send_message("请在下方选择!👇", view=GameSelectView())

bot.run("Token")

📌 完整代码(可直接复制)

Python
# discord.py 2.x / Python 3.8+
import discord
from discord.ext import commands

class GameSelect(discord.ui.Select):
    def __init__(self):
        options = [
            discord.SelectOption(label="我的世界", value="我的世界", description="用方块搭建的世界", emoji="⛏️"),
            discord.SelectOption(label="方舟:生存进化", value="方舟:生存进化", description="和恐龙一起求生!", emoji="🦖"),
            discord.SelectOption(label="无畏契约", value="无畏契约", description="5v5 战术 FPS", emoji="🔫"),
        ]
        super().__init__(placeholder="请选择你喜欢的游戏!", min_values=1, max_values=1, options=options)

    async def callback(self, interaction: discord.Interaction):
        await interaction.response.send_message(
            f"🎮 {interaction.user.mention} 选择了 **{self.values[0]}**!"
        )

class GameSelectView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=60)
        self.add_item(GameSelect())

intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    await bot.tree.sync()
    print(f"✅ {bot.user} 机器人已准备就绪!")

@bot.tree.command(name="게임선택", description="来选一个你喜欢的游戏吧!")
async def game_select(interaction: discord.Interaction):
    await interaction.response.send_message("请在下方选择!👇", view=GameSelectView())

bot.run("Token")

📌 运行结果

输入 /게임선택(即"选择游戏")后,机器人会发送一条带下拉菜单的消息;在菜单里选好游戏,就会收到"🎮 OO 选择了 我的世界!"这样的回复。

💡 附加内容:还有专门用来选择用户·身份组·频道的下拉菜单!使用 discord.ui.UserSelect、discord.ui.RoleSelect、discord.ui.ChannelSelect,就不用自己定义选项,服务器的用户/身份组/频道列表会自动显示出来。以后有机会再详细讲讲!

📌 常见错误

1. This interaction failed(交互失败)

callback 没有在 3 秒内响应时就会出现这个错误。如果处理需要较长时间,请先调用 await interaction.response.defer(),再用 interaction.followup.send() 回复即可。

2. 下拉菜单变成灰色、无法使用

超过 View(timeout=60) 设定的时间后,组件就会过期。如果菜单需要一直可用,请设置为 timeout=None。(如果想在机器人重启后也保留,需要使用 persistent view 并指定 custom_id,这部分会在进阶篇里讲!)

3. TypeError: __init__() got an unexpected keyword argument 'options'

把 options 传给 UserSelect 这类专用下拉菜单,而不是 discord.ui.Select 时,就会出现这个错误。自己定义选项时,一定要使用基础的 discord.ui.Select。

📌 总结

今天我们学习了如何用下拉菜单(Select Menu)整齐地放下最多 25 个选项。从按钮一路走到下拉菜单,下一篇我们来讲讲如何用模态框(Modal)让用户直接输入文本!敬请期待 🙌

📚 Discord 机器人开发系列

  1. Slash Command 完全攻略
  2. 为 Slash Command 添加选项(Arguments)
  3. 在 Slash Command 中添加子命令
  4. 用 Slash Command 发送 Embed
  5. 实现按钮(Button)交互
  6. 实现下拉菜单(Select Menu) ← 就是这篇!

连载 · 共 32 篇中的第 6 篇

Discord 机器人开发

  1. #1Discord 机器人开发 - Slash Command 完全攻略!
  2. #2为 Slash Command 添加选项(Arguments)!
  3. #3在 Slash Command 中添加子命令(Subcommand)!
  4. #4用 Slash Command 发送 Embed 嵌入消息!
  5. #5实现按钮(Button)交互!
  6. #6实现下拉菜单(Select Menu)!当前文章
  7. #7用模态框(Modal)接收用户输入(Python 示例)
  8. #8用嵌入消息(Embed)的图片和字段美化消息(Python 示例)
  9. #9接入 AI(Claude·ChatGPT API)!(Python 示例)
  10. #10支持多语言(i18n)!(Python 示例)
  11. #11用 Flask 制作网页仪表盘!(Python 示例)
  12. #12管理命令冷却时间(Cooldown)与权限(Permission)!(Python 示例)
  13. #13用身份组·频道自动化管理服务器!(Python 示例)
  14. #14保存数据!JSON vs SQLite(Python 示例)
  15. #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (韩语)
  16. #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (韩语)
  17. #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (韩语)
  18. #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (韩语)
  19. #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (韩语)
  20. #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (韩语)
  21. #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (韩语)
  22. #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (韩语)
  23. #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (韩语)
  24. #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (韩语)
  25. #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (韩语)
  26. #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (韩语)
  27. #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (韩语)
  28. #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (韩语)
  29. #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (韩语)
  30. #30打造投票·问卷(Poll)机器人!原生投票 + 按钮实时统计(Python 示例)🗳️
  31. #32打造服务器日志·审核日志(Audit Log)频道!自动记录消息删除、编辑、成员进出和踢出(Python 示例)🕵️
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (韩语)
显示全部 32 篇收起

作者

Mojangcam

亲手写代码、跑服务器、解决卡住的报错,把一路学到的东西记录下来的开发与 IT 实战博客