🤖

[Rust] DiscordのBOT作成 < serenity > - ⑤

2022/09/08に公開

ボタンの作成と応答

押されたボタンの名前を返す

  • 下記のようなボタンを作成し、押されたボタンの名前を返す


押されたボタンの名前を返す

ソースコード

  • このサンプルではボタンを各々作成しているが、ボタンの数が多い場合は列挙型などでまとめると管理しやすい
main.rs
use serenity::builder::{CreateActionRow, CreateButton};     // アクション関係のモジュール
use serenity::model::application::component::ButtonStyle;   // ボタンのスタイル

use std::time::Duration;        // タイムアウト用

~~~~~~~~~~中略~~~~~~~~~~

if msg.content == "!btn" {

    //----------ボタンAの作成----------
    let mut btn_a = CreateButton::default();

    btn_a.custom_id("Circle")
        .emoji('\u{2b55}')
        .label("マル")
        .style(ButtonStyle::Primary);

    //----------ボタンBの作成----------
    let mut btn_b = CreateButton::default();

    btn_b.custom_id("Cross")
        .emoji('\u{274c}')
        .label("バツ")
        .style(ButtonStyle::Primary);

    //----------アクションにボタンAとボタンBを追加----------
    let mut btns = CreateActionRow::default();

    btns.add_button(btn_a)
        .add_button(btn_b);

    //----------メッセージ(ボタン)の送信----------
    let m = msg.channel_id.send_message(&ctx, |m| {
            m.content("ボタンを選択してください")
                .components(|c| c.add_action_row(btns))
        })
        .await
        .expect("エラー");

    //----------インタラクションとタイムアウトの設定----------
    let mi = match m
        .await_component_interaction(&ctx)
        .timeout(Duration::from_secs(10))
        .await
    {
        Some(interaction) => interaction,
        None => {
            m.delete(&ctx).await.expect("エラー");
            msg.reply(&ctx, "タイムアウト").await.expect("エラー");
            return
        }
    };

    //----------ボタンAの作成----------
    m.delete(&ctx).await.expect("エラー");
            
    match &*mi.data.custom_id {
        "Circle"    => msg.reply(&ctx.http, "マル").await.expect("エラー"),
        "Cross"     => msg.reply(&ctx.http, "バツ").await.expect("エラー"),
        _           => {
            println!("エラー");
            return
        }
    };
}

クレートの設定

  • serenityfeatures内に"collector"を追加する
Cargo.toml
serenity = { version = "0.11.5", default-features = false, features = ["cache", "client", "collector", "gateway", "rustls_backend", "model"] }

ソースコード解説

ボタンの作成

  • CreateButton::default()
    • ボタンのオブジェクトを作成する

  • .custom_id()
    • ボタンのID(名前)を設定する

  • .emoji()
    • ボタン上に表示する絵文字を設定する

  • .label()
    • ボタン上に表示するテキストを設定する

  • .style()
    • ボタンのスタイルを設定する
ボタンの作成
let mut btn_a = CreateButton::default();

btn_a.custom_id("Circle")
    .emoji('\u{2b55}')
    .label("マル")
    .style(ButtonStyle::Primary);

  • ボタンのスタイルには以下のようなものがある
ボタンのスタイル
.style(ButtonStyle::Primary);
.style(ButtonStyle::Secondary);
.style(ButtonStyle::Success);
.style(ButtonStyle::Danger);


ボタンのスタイル

アクションにボタンを追加

  • CreateActionRow::default()
    • アクションのオブジェクトを作成する

  • .add_button()
    • アクションのオブジェクトに作成したボタンを追加する
アクションにボタンを追加
let mut act = CreateActionRow::default();

act.add_button(btn_a)
    .add_button(btn_b);

メッセージ(ボタン)の送信

  • ボタンの送信には.send_message()を使う

  • .components()
    • .send_message()で送信するテキスト以外のコンポーネント(ここではボタン)をセットする

  • .add_action_row()
    • コンポーネントにアクションのオブジェクトを追加する
メッセージ(ボタン)の送信
let m = msg.channel_id.send_message(&ctx, |m| {
    m.content("ボタンを選択してください")
        .components(|c| c.add_action_row(act))
    })
    .await
    .expect("エラー");

インタラクションとタイムアウトの設定

  • .await_component_interaction()
    • 送信したメッセージ(ここではボタン)に対してのインタラクション(ユーザーがボタンを押す動作)を待つ

  • .timeout()
    • インタラクションの待機時間を設定する
    • Duration::from_secs(10)によって10秒が設定される

  • インタラクションが時間内に行われた場合、Some(interaction)が返されmiにインタラクション結果(interaction)を取り込む
  • インタラクションがタイムアウトした場合、Noneが返されNone => { }を実行する
インタラクションとタイムアウトの設定
let mi = match m
        .await_component_interaction(&ctx)
        .timeout(Duration::from_secs(10))
        .await
    {
        Some(interaction) => interaction,
        None => {
            m.delete(&ctx).await.expect("エラー");
            msg.reply(&ctx, "タイムアウト").await.expect("エラー");
            return
        }
    };

インタラクションに対する応答

  • .delete()を使用して送信したメッセージ(ここではボタン)を削除し、押されたボタンのID( mi.data.custom_id)に合わせたリプライを返す
インタラクションに対する応答
m.delete(&ctx).await.expect("エラー");
            
match &*mi.data.custom_id {
    "Circle"    => msg.reply(&ctx.http, "マル").await.expect("エラー"),
    "Cross"     => msg.reply(&ctx.http, "バツ").await.expect("エラー"),
    _           => {
        println!("エラー");
        return
    }
};

Discussion