owned this note
owned this note
Published
Linked with GitHub
---
tags: 1102,Discord Bot
---
# 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)])])
```
----

----
### 讓機器人做出回應
先等待使用者選取完選項
```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
- 如果你開了很多個選單,可能會造成選一次選單後機器人會輸出好幾次

----
### 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)
```