LoginSignup
8
7

【discord.py v2.0】ボタンやセレクトメニュー等を利用する方法

Last updated at Posted at 2023-02-13

はじめに

 この記事は、discord.py v2.0より利用できるようになったBot UIキットについての解説を行う。
Bot UIキットは、Botにボタンやセレクトメニュー、テキストインプットなどのv2.0で追加された部品を扱う際に利用する。
 v2.0で追加されたBOT UIキットに関連するアップデートは非常に豊富であるため、当記事ではよく利用するパターンと要素を抜粋して紹介する。

クイックスタート

 はじめにBOT UIキットの基本となるdiscord.ui.Viewの最小構成を紹介する。

import discord
import discord.ext import commands

bot = commands.Bot(command_prefix="?", intents=discord.Intents.all())

class SampleView(discord.ui.View): # UIキットを利用するためにdiscord.ui.Viewを継承する
    def __init__(self, timeout=180): # Viewにはtimeoutがあり、初期値は180(s)である
        super().__init__(timeout=timeout)

@bot.command()
async def test(ctx):
    view = SampleView(timeout=None)
    await ctx.send(view=view)

bot.run("YOUR BOT TOKEN")

 上記のプログラムは?testというコマンドを入力すると、そのチャンネルにViewを返すというものである。ここで言うViewとはdiscord.ui.Viewを継承し、作成したSampleViewクラスである。このプログラムでは、Viewに部品を設定していないため、見かけ上BOTからは何も返ってこない。これ以降、継承したクラスにボタンやセレクトメニューなどの部品を配置していくことになる。
 補足として、上記プログラムのコメントでも明記しているようにViewにはタイムアウトが存在し、タイムアウトするとViewの要素(ボタンなど)のイベントを取得出来なくなってしまう。デフォルトでは180(s)だが、Noneにすることによってタイムアウトを無効化することができる。

ボタンの追加

 これ以降のサンプルでは、簡略化のためdiscord.ui.Viewを継承したSampleViewクラスのみを提示する。前後のコード等は前章のクイックスタートを参照のこと。

class SampleView(discord.ui.View):
    def __init__(self, timeout=180):
        super().__init__(timeout=timeout)
    
    @discord.ui.button(label="OK", style=discord.ButtonStyle.success)
    async def ok(self, button: discord.ui.Button, interaction: discord.Interaction):
        await interaction.response.send_message(f"{interaction.user.mention} OK!")

    @discord.ui.button(label="NG", style=discord.ButtonStyle.gray)
    async def ng(self, button: discord.ui.Button, interaction: discord.Interaction):
        await interaction.response.send_message(f"{interaction.user.mention} NG")

e94cbb5ff622eac383e38bc5a9847c04.png
 上記のプログラムでは、「OK」「NG」の2種類のボタンを作成し、ボタンを押したユーザーに対してそれぞれメンション付きで「OK!」と「NG」を返信するものである。
 @discord.ui.buttonのlabelには、ボタンの名前を記述し、styleにはボタンの色などのスタイルを指定する。スタイルの種類に関しては公式ドキュメントを参照。
 引数interactionには、押されたボタンに関する情報が格納されており、例のようにinteraction.userなどとすることでボタンを押したユーザーの情報を取得することができる。また、discordではinteractionが発行されてから3秒以内にinteractionのresponseを返すように推奨しており、これを満たさない場合は、ボタンの下部に「インタラクションに失敗しました」というメッセージが表示される。あくまでも推奨されているだけなので、返さないと処理が無効化されるということはない。今回は、responseとしてsend_message関数を利用して、ユーザーにメンションを返している。

「インタラクションに失敗しました」対策

4d60d439a7ede0e3a3a1172772df73d2.png
 前の章で述べたようにinteractionは3秒以内にresponseを発行しないと「インタラクションに失敗しました」というメッセージを表示してしまう問題に対する対策は空メッセージを送ることである。

await interaction.response.send_message("")

 上記の例のように空メッセージを送ると、responseはされたものとして判定され「インタラクションに失敗しました」というメッセージを表示させることを防止する。これはボタンの入力により、メッセージを返したくない場合に非常に有効である。

セレクトメニューの追加

class SampleView(discord.ui.View):
    def __init__(self, timeout=180):
        super().__init__(timeout=timeout)

    @discord.ui.select(
        cls=discord.ui.Select,
        placeholder="What is your favorite fruit?",
        options=[
            discord.SelectOption(label="Banana"),
            discord.SelectOption(label="Apple"),
            discord.SelectOption(label="Pineapple"),
            discord.SelectOption(label="Grapefruit"),
            discord.SelectOption(label="Orange"),
        ]
    )
    async def select(self, interaction: discord.Interaction, select: discord.ui.Select):
        await interaction.response.send_message(f"{interaction.user.mention} {select.values[0]}")

b7f8b35bf27bb5cecfe4b71249491673.png
5209ac4f38475ead56b0720c9dec79a7.png
 上記のプログラムでは、5種類の選択肢を持つセレクトメニューを追加し、ボタンを押したユーザーに対してそれぞれメンション付きで選択した選択肢を返信する。
 @discord.ui.selectのclsには、セレクトメニューの種類を表すクラスを指定する。今回、指定しているdiscord.ui.Selectは一番基本的なクラスで、ユーザーが任意に選択肢を設定することができる。選択肢はdiscord.ui.Selectの場合は、optionsにdiscord.SelectOptionのリストとしてそれぞれlabelを設定することで実現できる。選択肢のクラスは他にも、サーバー内のロールやチャンネルを選択できるもの等、複数種類存在する。詳細は公式ドキュメントを参照。

おわりに

 当記事で紹介した要素以外にもv2.0で追加されたUI関連のアップデートでは、TextInputなどをModal(Modelではない)を利用して設置することができる。また、こちらのほうも機会があれば紹介しようと思う。最後に改めて、詳細な情報を得られたい方は公式ドキュメントを参照されたい。
 

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7