카테고리: 디스코드 봇 만들기

디스코드 봇 만들기#6드롭다운(Select Menu) 메뉴 구현하기!

목차8개 항목

안녕하세요! Mojangcam입니다 😎

지난 #5편에서는 버튼(Button)으로 봇과 상호작용하는 방법을 알아봤죠? 이번에는 한 단계 더 나아가서 드롭다운 메뉴(Select Menu) 를 만들어보겠습니다!

버튼은 선택지가 2~3개일 때 좋지만, 선택지가 5개 이상 되면 화면이 버튼으로 가득 차버립니다. 이럴 때 드롭다운 메뉴를 쓰면 최대 25개의 선택지를 깔끔하게 하나의 메뉴에 담을 수 있어요. 역할 선택, 설문조사, 게임 서버 선택 메뉴 같은 곳에 정말 많이 쓰입니다!

📌 준비물

  • Python 3.8 이상
  • discord.py 2.x (Select Menu는 2.0부터 지원됩니다!)
  • 봇 토큰 + 서버에 봇 초대 완료 (시리즈 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="5대5 택티컬 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")

📌 전체 코드 (복붙 OK)

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="5대5 택티컬 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'

discord.ui.Select 가 아니라 UserSelect 같은 전용 셀렉트에 options 를 넘기면 나는 에러예요. 직접 선택지를 정의할 때는 반드시 기본 discord.ui.Select 를 사용하세요.

📌 마무리

오늘은 드롭다운(Select Menu)으로 최대 25개의 선택지를 깔끔하게 담는 방법을 알아봤어요. 버튼 → 드롭다운까지 왔으니, 다음 편에서는 모달(Modal)로 유저에게 직접 텍스트 입력을 받는 방법을 다뤄볼게요! 기대해주세요 🙌

📚 디스코드 봇 만들기 시리즈

  1. Slash Command 완전 정복
  2. Slash Command에 옵션(Arguments) 추가하기
  3. Slash Command에 서브 커맨드 넣기
  4. Slash Command로 임베드 전송하기
  5. 버튼(Button) 상호작용 구현하기
  6. 드롭다운(Select Menu) 메뉴 구현하기 ← 지금 이 글!

연재 · 32편 중 6번째

디스코드 봇 만들기

  1. #1디스코드 봇 만들기 - Slash Command 완전 정복!
  2. #2Slash Command에 옵션(Arguments) 추가하기!
  3. #3Slash Command에 서브 커맨드(Subcommand) 넣기!
  4. #4Slash Command로 임베드 전송하기!
  5. #5버튼(Button) 상호작용 구현하기!
  6. #6드롭다운(Select Menu) 메뉴 구현하기!지금 읽는 글
  7. #7모달(Modal)로 입력 받기 구현하기 (파이썬 예제)
  8. #8임베드(Embed) 이미지·필드로 꾸미기 (파이썬 예제)
  9. #9AI(Claude·ChatGPT API) 연동하기! (파이썬 예제)
  10. #10다국어(i18n) 지원하기! (파이썬 예제)
  11. #11플라스크(Flask)로 웹 대시보드 만들기! (파이썬 예제)
  12. #12명령어 쿨다운(Cooldown)·권한(Permission) 관리하기! (파이썬 예제)
  13. #13역할·채널 자동화로 서버 관리하기! (파이썬 예제)
  14. #14데이터 저장하기! JSON vs SQLite (파이썬 예제)
  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) 봇 만들기! 네이티브 투표 + 버튼으로 실시간 집계까지 (파이썬 예제) 🗳️
  31. #32서버 로그·감사(Audit Log) 채널 만들기! 메시지 삭제·수정·입퇴장·추방까지 자동 기록 (파이썬 예제) 🕵️
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉
전체 32편 보기접기

글쓴이

Mojangcam

직접 코드를 짜고, 서버를 돌리고, 막힌 에러를 해결하며 배운 것들을 기록하는 개발·IT 실전 기록 블로그