# Discord Bot#5 Menu Role --- ## DEMO --- ## 前置作業 ---- ### 下載 discord_components ``` pip install discord_components ``` ---- ### 在Cog資料夾底下新增menu. py ```python= import discord from discord.ext import commands from discord_components import Select, SelectOption class Menu(commands.Cog): def __init__(self, bot): self.bot = bot def setup(bot): bot.add_cog(Menu(bot)) ``` --- ## Menu ---- ### Menu 參數 - placeholder: 選單上面的文字 - SelectOption: 選單的選項 - label: 每個選項上的文字 - value: 選擇這個選項後回傳給程式的變數 ---- ### A simple example ```python= @ commands.command() async def test(self, ctx): await ctx.send(components=[ Select(placeholder='Is python easy to learn?', options=[ SelectOption(label='Yes', value=1), SelectOption(label='Nope', value=0)])]) ``` ---- ![](https://i.imgur.com/myehezK.png) ---- ### 讓機器人做出回應 先等待使用者選取完選項 ```python= interaction = await self.bot.wait_for("select_option") ``` ---- ### wait_for(event) - 讓機器人可以在這個函式暫時停下來,直到參數中的 event 發生 - "select_option" 是 discord_component 額外定義的事件,代表使用者選取完表單,並回傳選取的資訊 ---- ### 根據變數做出反應 ```py interaction = await self.bot.wait_for("select_option") res = interaction.values[0] if res == '1': await ctx.send('very good!') else: await ctx.send('QQ') ``` ---- ### 重複使用這個表單 加個 while True 迴圈,和一點小魔法即可 ```python= while True: interaction = await self.bot.wait_for("select_option") res = interaction.values[0] if res == '1': await ctx.send('very good!') else: await ctx.send('QQ') # 黑魔法 await interaction.respond(type=6) ``` ---- ### 一點小 BUG - 如果你開了很多個選單,可能會造成選一次選單後機器人會輸出好幾次 ![](https://i.imgur.com/ycgZ1T3.png) ---- ### WHY? - 原因與 while True 迴圈有關 - 實際上之前叫出的表單會都在背景執行 - 假設你開個三個選單,只要在一個選單中選一個選項後,三個選單的 wait_for 都會讀取到資料 ---- ### 加上時間戳記 記得導入時間相關的套件 ```python= from datetime import datetime ``` ---- ### 將每個選單的 ID 設為時間戳記 ```python= timestamp = datetime.timestamp(datetime.now()) await ctx.send(components=[ Select(placeholder='Is python easy to learn?', options=[ SelectOption(label='Yes', value=1), SelectOption(label='Nope', value=0)], custom_id=str(timestamp))]) ``` ---- ### 修改 wait_for 參數 每個選單只在這個選單對應時間戳記才會運作 ```python= interaction = await self.bot.wait_for("select_option", check=lambda inter: inter.custom_id == str(timestamp)) ``` ---- ### Example ```python= @ commands.command() async def test(self, ctx): timestamp = datetime.timestamp(datetime.now()) await ctx.send(components=[ Select(placeholder='Is python easy to learn?', options=[ SelectOption(label='Yes', value=1), SelectOption(label='Nope', value=0)], custom_id=str(timestamp))]) while True: interaction = await self.bot.wait_for("select_option", check=lambda inter: inter.custom_id == str(timestamp)) res = interaction.values[0] if res == '1': await ctx.send('very good!') else: await ctx.send('QQ') await interaction.respond(type=6) ``` --- ## 加上身分組功能 ---- ### 在程式最前面建立一個身分組 list ```python= role = ['第一個身分組的 ID', '第二個身分組的 ID'] ``` ---- ### add_roles ```python= async def add_roles(self, ctx, user, roleIDList): roleList = [] for i in roleIDList: role = ctx.guild.get_role(int(i)) roleList.append(role) await user.add_roles(*roleList) ``` ---- ### remove_roles ```python= async def remove_roles(self, ctx, user, roleIDList): roleList = [] for i in roleIDList: role = ctx.guild.get_role(int(i)) roleList.append(role) await user.remove_roles(*roleList) ``` ---- ### Note - 這兩個函式並不是指令,不需要加上@ commands.command() - 在一個 list 前面加上星號,可以當作一次送入多個參數 ---- ### 選取多個選項 - 把Select選單的物件加上一些參數 - min_values: 最少可以選幾個選項 - max_value: 最多可以選幾個選項 - interaction.values 實際上會包含所有選取的選項的 value ---- ### Example ```python= await ctx.send('Get the roles!', components=[ Select(placeholder='Select your role!', options=[ SelectOption(label='roleA', value=role[0]), SelectOption(label='roleB', value=role[1])] , min_values=0, max_values=2, custom_id=str(timestamp))]) ``` ---- ### 依照選單內容給予身分組 - 把所有選取的身分組新增到 "選單的使用者" - 對使用者移除剩下的身分組(沒有點選的) ---- ### 差集 - interaction.values 內容為我們要新增的身分組 - 所有的身分組 (先前建立的 role list) 與 interaction.values 的差集,即是要移除的身分組 ```python= list(set(role).difference(interaction.values) ``` ---- ### 大功告成! ```python= @ commands.command() async def rolelist(self, ctx): timestamp = datetime.timestamp(datetime.now()) await ctx.send('Get the roles!', components=[ Select(placeholder='Select your role!', options=[ SelectOption(label='roleA', value=role[0]), SelectOption(label='roleB', value=role[1])], min_values=0, max_values=2, custom_id=str(timestamp))]) while True: interaction = await self.bot.wait_for("select_option", check=lambda inter: inter.custom_id == str(timestamp)) await self.add_roles(ctx, interaction.user, interaction.values) await self.remove_roles(ctx, interaction.user, list(set(role).difference(interaction.values))) await interaction.respond(type=6) ```
{"metaMigratedAt":"2023-06-17T01:06:32.859Z","metaMigratedFrom":"YAML","title":"Discord Bot#5 Menu Role","breaks":true,"contributors":"[{\"id\":\"e66eff6e-ecb8-470a-a384-ea2a02e04747\",\"add\":7175,\"del\":1953}]"}
    560 views
   owned this note