Discord.py disabling buttons after they have been clicked

274 Views Asked by At

I have two buttons which I want them both to be disabled on the original message it was clicked on after one of them has been clicked. Even better than just disabling them I would like them to be removed from the original message, but that isn't something I need.

My current code:

import discord
from discord.ext import commands
from discord.ui import Button, button, View

# Class
class MyView(View):
    def __init__(self):
        super().__init__(timeout=None)

    @button(label="Hello!", style=discord.ButtonStyle.blurple)
    async def hello(self, interaction: discord.Interaction, button: Button):
        button.disabled=True
        embedHelloButton=discord.Embed(title="Hi There!", color=0x5865F2)
        embedHelloButton.set_author(name=f"Requested by {interaction.user.name}", icon_url=interaction.user.avatar.url)
        await interaction.response.send_message(embed=embedHelloButton, ephemeral=False)
    
    @button(label="No. Bye.", style=discord.ButtonStyle.red)
    async def bye(self, interaction: discord.Interaction, button: Button):
        button.disabled=True
        embedByeButton=discord.Embed(title="Bye :(", color=0xff0000)
        embedByeButton.set_author(name=f"Requested by {interaction.user.name}", icon_url=interaction.user.avatar.url)
        await interaction.response.send_message(embed=embedByeButton, ephemeral=False)

# Command
@client.hybrid_command(name="hello", description="Say hello to the bot!")
async def hello(ctx):
    embedHello=discord.Embed(title="Say hello to me!", color=0xff0000)
    embedHello.set_author(name=f"Requested by {ctx.author.name}", icon_url=ctx.author.avatar.url)
    await ctx.send(embed=embedHello, view=MyView())

My Output: The output of my code

The buttons on the first message are still clickable and I want the buttons to either be disabled on that first message or for them to be removed completely. Any solutions?

1

There are 1 best solutions below

0
TimG233 On BEST ANSWER

You could simply make these changes to your view class to disable both buttons

class MyView(View):
  # do what you just did
  @button(label="Hello!", style=discord.ButtonStyle.blurple)
  async def hello(self, interaction: discord.Interaction, button: Button):
    # do sth
    # example to disable both buttons by clicking 'hello' button
    button.disabled = True  # disable the 'hello' button
    bye_btn = discord.utils.get(self.children, label="No. Bye.")  # get the 'bye' button
    bye_btn.disabled = True
    # send a msg or sth else

If you would like to remove all buttons, it is even easier than disabling buttons

class MyView(View):
  @button(label="Hello!", style=discord.ButtonStyle.blurple)
  async def hello(self, interaction: discord.Interaction, button: Button):
    # do sth
    await interaction.response.edit_message(view=None)  # this will remove all the components in the class

And I would suggest changing your slash command slightly

@client.hybrid_command(name="hello", description="Say hello to the bot!")
async def hello(ctx):
    # do your embed stuff
    # the good way to do this is that you could access your message (in your view class) by 'self.message'
    # because functions like 'on_timeout' does not have 'interaction' param.
    view = MyView()
    view.message = await ctx.send(embed=embedHello, view=view)

And just as a quick reminder, you could only respond to the interaction once to avoid triggering interaction responded exception. So, if you would like to send a message and edit the view, you can switch to followup

class MyView(View):
  @button(label="Hello!", style=discord.ButtonStyle.blurple)
  async def hello(self, interaction: discord.Interaction, button: Button):
    await interaction.response.defer()
    # do sth
    await interaction.followup.send(content='...', ...)  # send the message you want
    await interaction.followup.edit_message(message_id=self.message.id, view=None)  # message_id is mandatory here

Hope this would help.