Тема 5 из 6

Кнопки

Набирать ответы текстом медленно. В discord.py под сообщением можно разместить кнопки — и обрабатывать нажатия прямо в коде.

View и кнопки

class VoteView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=180)       # через 180 секунд кнопки перестанут работать
        self.votes = {}

    @discord.ui.button(label="За", style=discord.ButtonStyle.success)
    async def yes(self, interaction: discord.Interaction, button: discord.ui.Button):
        await interaction.response.send_message("Голос принят", ephemeral=True)


await message.channel.send("Играем ещё раунд?", view=VoteView())
  • View — набор элементов под сообщением и их обработчики; у каждого сообщения — свой объект View со своими данными (self.votes);
  • @discord.ui.button(label=…, style=…) превращает метод в кнопку; стили — primary (синяя), success (зелёная), danger (красная), secondary (серая);
  • метод получает interaction — нажатие: interaction.user — кто нажал, interaction.response — как ответить.

Ответ на нажатие

На каждое нажатие нужно ответить ровно один раз:

await interaction.response.send_message("Текст")                    # новое сообщение
await interaction.response.send_message("Только вам", ephemeral=True) # видит только нажавший
await interaction.response.edit_message(content="Новый текст", view=self)   # изменить сообщение с кнопками

Если не ответить за 3 секунды, Discord покажет пользователю «Ошибка взаимодействия».

Менять кнопки

button.label = "Нажато: 5"
button.disabled = True
for item in self.children:      # все элементы View
    item.disabled = True
await interaction.response.edit_message(view=self)

Изменения появятся у пользователей только после edit_message(view=self). Сначала меняйте кнопки, потом обновляйте сообщение. self.stop() завершает View — больше нажатий он не ждёт.

Кнопки в цикле

Если варианты заранее неизвестны (вопросы викторины), кнопки создают в цикле:

for option in options:
    button = discord.ui.Button(label=option)
    button.callback = self.make_handler(button)
    self.add_item(button)

Функция-фабрика make_handler(button) возвращает обработчик, который «помнит» свою кнопку.

Итог

  • discord.ui.View, @discord.ui.button(label, style), channel.send(…, view=…);
  • interaction.user, interaction.response.send_message / edit_message, ephemeral=True;
  • button.label, button.disabled, self.children, затем edit_message(view=self);
  • кнопки в цикле: discord.ui.Button, callback, add_item.