mirror of
				https://github.com/Rapptz/discord.py.git
				synced 2025-10-31 05:23:03 +00:00 
			
		
		
		
	Add examples for how to use views
This commit is contained in:
		
							
								
								
									
										57
									
								
								examples/views/confirm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								examples/views/confirm.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| from discord.ext import commands | ||||
|  | ||||
| import discord | ||||
|  | ||||
|  | ||||
| class Bot(commands.Bot): | ||||
|     def __init__(self): | ||||
|         super().__init__(command_prefix=commands.when_mentioned_or('$')) | ||||
|  | ||||
|     async def on_ready(self): | ||||
|         print(f'Logged in as {self.user} (ID: {self.user.id})') | ||||
|         print('------') | ||||
|  | ||||
|  | ||||
| # Define a simple View that gives us a confirmation menu | ||||
| class Confirm(discord.ui.View): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.value = None | ||||
|  | ||||
|     # When the confirm button is pressed, set the inner value to `True` and | ||||
|     # stop the View from listening to more input. | ||||
|     # We also send the user an ephemeral message that we're confirming their choice. | ||||
|     @discord.ui.button(label='Confirm', style=discord.ButtonStyle.green) | ||||
|     async def confirm(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         await interaction.response.send_message('Confirming', ephemeral=True) | ||||
|         self.value = True | ||||
|         self.stop() | ||||
|  | ||||
|     # This one is similar to the confirmation button except sets the inner value to `False` | ||||
|     @discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey) | ||||
|     async def cancel(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         await interaction.response.send_message('Cancelling', ephemeral=True) | ||||
|         self.value = False | ||||
|         self.stop() | ||||
|  | ||||
|  | ||||
| bot = Bot() | ||||
|  | ||||
|  | ||||
| @bot.command() | ||||
| async def ask(ctx: commands.Context): | ||||
|     """Asks the user a question to confirm something.""" | ||||
|     # We create the view and assign it to a variable so we can wait for it later. | ||||
|     view = Confirm() | ||||
|     await ctx.send('Do you want to continue?', view=view) | ||||
|     # Wait for the View to stop listening for input... | ||||
|     await view.wait() | ||||
|     if view.value is None: | ||||
|         print('Timed out...') | ||||
|     elif view.value: | ||||
|         print('Confirmed...') | ||||
|     else: | ||||
|         print('Cancelled...') | ||||
|  | ||||
|  | ||||
| bot.run('token') | ||||
							
								
								
									
										43
									
								
								examples/views/counter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								examples/views/counter.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| from discord.ext import commands | ||||
|  | ||||
| import discord | ||||
|  | ||||
|  | ||||
| class CounterBot(commands.Bot): | ||||
|     def __init__(self): | ||||
|         super().__init__(command_prefix=commands.when_mentioned_or('$')) | ||||
|  | ||||
|     async def on_ready(self): | ||||
|         print(f'Logged in as {self.user} (ID: {self.user.id})') | ||||
|         print('------') | ||||
|  | ||||
|  | ||||
| # Define a simple View that gives us a counter button | ||||
| class Counter(discord.ui.View): | ||||
|  | ||||
|     # Define the actual button | ||||
|     # When pressed, this increments the number displayed until it hits 5. | ||||
|     # When it hits 5, the counter button is disabled and it turns green. | ||||
|     # note: The name of the function does not matter to the library | ||||
|     @discord.ui.button(label='0', style=discord.ButtonStyle.red) | ||||
|     async def count(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         number = int(button.label) if button.label else 0 | ||||
|         if number + 1 >= 5: | ||||
|             button.style = discord.ButtonStyle.green | ||||
|             button.disabled = True | ||||
|         button.label = str(number + 1) | ||||
|  | ||||
|         # Make sure to update the message with our updated selves | ||||
|         await interaction.response.edit_message(view=self) | ||||
|  | ||||
|  | ||||
| bot = CounterBot() | ||||
|  | ||||
|  | ||||
| @bot.command() | ||||
| async def counter(ctx: commands.Context): | ||||
|     """Starts a counter for pressing.""" | ||||
|     await ctx.send('Press!', view=Counter()) | ||||
|  | ||||
|  | ||||
| bot.run('token') | ||||
							
								
								
									
										47
									
								
								examples/views/ephemeral.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								examples/views/ephemeral.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| from discord.ext import commands | ||||
|  | ||||
| import discord | ||||
|  | ||||
| class EphemeralCounterBot(commands.Bot): | ||||
|     def __init__(self): | ||||
|         super().__init__(command_prefix=commands.when_mentioned_or('$')) | ||||
|  | ||||
|     async def on_ready(self): | ||||
|         print(f'Logged in as {self.user} (ID: {self.user.id})') | ||||
|         print('------') | ||||
|  | ||||
| # Define a simple View that gives us a counter button | ||||
| class Counter(discord.ui.View): | ||||
|  | ||||
|     # Define the actual button | ||||
|     # When pressed, this increments the number displayed until it hits 5. | ||||
|     # When it hits 5, the counter button is disabled and it turns green. | ||||
|     # note: The name of the function does not matter to the library | ||||
|     @discord.ui.button(label='0', style=discord.ButtonStyle.red) | ||||
|     async def count(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         number = int(button.label) if button.label else 0 | ||||
|         if number + 1 >= 5: | ||||
|             button.style = discord.ButtonStyle.green | ||||
|             button.disabled = True | ||||
|         button.label = str(number + 1) | ||||
|  | ||||
|         # Make sure to update the message with our updated selves | ||||
|         await interaction.response.edit_message(view=self) | ||||
|  | ||||
| # Define a View that will give us our own personal counter button | ||||
| class EphemeralCounter(discord.ui.View): | ||||
|     # When this button is pressed, it will respond with a Counter view that will | ||||
|     # give the button presser their own personal button they can press 5 times. | ||||
|     @discord.ui.button(label='Click', style=discord.ButtonStyle.blurple) | ||||
|     async def receive(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         # ephemeral=True makes the message hidden from everyone except the button presser | ||||
|         await interaction.response.send_message('Enjoy!', view=Counter(), ephemeral=True) | ||||
|  | ||||
| bot = EphemeralCounterBot() | ||||
|  | ||||
| @bot.command() | ||||
| async def counter(ctx: commands.Context): | ||||
|     """Starts a counter for pressing.""" | ||||
|     await ctx.send('Press!', view=EphemeralCounter()) | ||||
|  | ||||
| bot.run('token') | ||||
							
								
								
									
										60
									
								
								examples/views/persistent.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								examples/views/persistent.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| from discord.ext import commands | ||||
| import discord | ||||
|  | ||||
|  | ||||
| class PersistentViewBot(commands.Bot): | ||||
|     def __init__(self): | ||||
|         super().__init__(command_prefix=commands.when_mentioned_or('$')) | ||||
|  | ||||
|     async def on_ready(self): | ||||
|         print(f'Logged in as {self.user} (ID: {self.user.id})') | ||||
|         print('------') | ||||
|  | ||||
|  | ||||
| # Define a simple View that persists between bot restarts | ||||
| # In order a view to persist between restarts it needs to meet the following conditions: | ||||
| # 1) The timeout of the View has to be set to None | ||||
| # 2) Every item in the View has to have a custom_id set | ||||
| # It is recommended that the custom_id be sufficiently unique to | ||||
| # prevent conflicts with other buttons the bot sends. | ||||
| # For this example the custom_id is prefixed with the name of the bot. | ||||
| # Note that custom_ids can only be up to 100 characters long. | ||||
| class PersistentView(discord.ui.View): | ||||
|     def __init__(self): | ||||
|         super().__init__(timeout=None) | ||||
|  | ||||
|     @discord.ui.button(label='Green', style=discord.ButtonStyle.green, custom_id='persistent_view:green') | ||||
|     async def green(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         await interaction.response.send_message('This is green.', ephemeral=True) | ||||
|  | ||||
|     @discord.ui.button(label='Red', style=discord.ButtonStyle.red, custom_id='persistent_view:red') | ||||
|     async def red(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         await interaction.response.send_message('This is red.', ephemeral=True) | ||||
|  | ||||
|     @discord.ui.button(label='Grey', style=discord.ButtonStyle.grey, custom_id='persistent_view:grey') | ||||
|     async def grey(self, button: discord.ui.Button, interaction: discord.Interaction): | ||||
|         await interaction.response.send_message('This is grey.', ephemeral=True) | ||||
|  | ||||
|  | ||||
| bot = PersistentViewBot() | ||||
|  | ||||
| # Register the persistent view for listening | ||||
| # Note that this does not send the view to any message. | ||||
| # In order to do this you need to first send a message with the View, which is shown below. | ||||
| # If you have the message_id you can also pass it as a keyword argument, but for this example | ||||
| # we don't have one. | ||||
| bot.add_view(PersistentView()) | ||||
|  | ||||
|  | ||||
| @bot.command() | ||||
| @commands.is_owner() | ||||
| async def prepare(ctx: commands.Context): | ||||
|     """Starts a persistent view.""" | ||||
|     # In order for a persistent view to be listened to, it needs to be sent to an actual message. | ||||
|     # Call this method once just to store it somewhere. | ||||
|     # In a more complicated program you might fetch the message_id from a database for use later. | ||||
|     # However this is outside of the scope of this simple example. | ||||
|     await ctx.send("What's your favourite colour?", view=PersistentView()) | ||||
|  | ||||
|  | ||||
| bot.run('token') | ||||
							
								
								
									
										139
									
								
								examples/views/tic_tac_toe.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								examples/views/tic_tac_toe.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | ||||
| from typing import List | ||||
| from discord.ext import commands | ||||
| import discord | ||||
|  | ||||
| # Defines a custom button that contains the logic of the game. | ||||
| # The ['TicTacToe'] bit is for type hinting purposes to tell your IDE or linter | ||||
| # what the type of `self.view` is. It is not required. | ||||
| class TicTacToeButton(discord.ui.Button['TicTacToe']): | ||||
|     def __init__(self, x: int, y: int): | ||||
|         # A label is required, but we don't need one so a zero-width space is used | ||||
|         # The row parameter tells the View which row to place the button under. | ||||
|         # A View can only contain up to 5 rows -- each row can only have 5 buttons. | ||||
|         # Since a Tic Tac Toe grid is 3x3 that means we have 3 rows and 3 columns. | ||||
|         super().__init__(style=discord.ButtonStyle.secondary, label='\u200b', row=y) | ||||
|         self.x = x | ||||
|         self.y = y | ||||
|  | ||||
|     # This function is called whenever this particular button is pressed | ||||
|     # This is part of the "meat" of the game logic | ||||
|     async def callback(self, interaction: discord.Interaction): | ||||
|         assert self.view is not None | ||||
|         view: TicTacToe = self.view | ||||
|         state = view.board[self.y][self.x] | ||||
|         if state in (view.X, view.O): | ||||
|             return | ||||
|  | ||||
|         if view.current_player == view.X: | ||||
|             self.style = discord.ButtonStyle.danger | ||||
|             self.label = 'X' | ||||
|             self.disabled = True | ||||
|             view.board[self.y][self.x] = view.X | ||||
|             view.current_player = view.O | ||||
|             content = "It is now O's turn" | ||||
|         else: | ||||
|             self.style = discord.ButtonStyle.success | ||||
|             self.label = 'O' | ||||
|             self.disabled = True | ||||
|             view.board[self.y][self.x] = view.O | ||||
|             view.current_player = view.X | ||||
|             content = "It is now X's turn" | ||||
|  | ||||
|         winner = view.check_board_winner() | ||||
|         if winner is not None: | ||||
|             if winner == view.X: | ||||
|                 content = 'X won!' | ||||
|             elif winner == view.O: | ||||
|                 content = 'O won!' | ||||
|             else: | ||||
|                 content = "It's a tie!" | ||||
|  | ||||
|             for child in view.children: | ||||
|                 child.disabled = True | ||||
|  | ||||
|             view.stop() | ||||
|  | ||||
|         await interaction.response.edit_message(content=content, view=view) | ||||
|  | ||||
|  | ||||
| # This is our actual board View | ||||
| class TicTacToe(discord.ui.View): | ||||
|     # This tells the IDE or linter that all our children will be TicTacToeButtons | ||||
|     # This is not required | ||||
|     children: List[TicTacToeButton] | ||||
|     X = -1 | ||||
|     O = 1 | ||||
|     Tie = 2 | ||||
|  | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.current_player = self.X | ||||
|         self.board = [ | ||||
|             [0, 0, 0], | ||||
|             [0, 0, 0], | ||||
|             [0, 0, 0], | ||||
|         ] | ||||
|  | ||||
|         # Our board is made up of 3 by 3 TicTacToeButtons | ||||
|         # The TicTacToeButton maintains the callbacks and helps steer | ||||
|         # the actual game. | ||||
|         for x in range(3): | ||||
|             for y in range(3): | ||||
|                 self.add_item(TicTacToeButton(x, y)) | ||||
|  | ||||
|     # This method checks for the board winner -- it is used by the TicTacToeButton | ||||
|     def check_board_winner(self): | ||||
|         for across in self.board: | ||||
|             value = sum(across) | ||||
|             if value == 3: | ||||
|                 return self.O | ||||
|             elif value == -3: | ||||
|                 return self.X | ||||
|  | ||||
|         # Check vertical | ||||
|         for line in range(3): | ||||
|             value = self.board[0][line] + self.board[1][line] + self.board[2][line] | ||||
|             if value == 3: | ||||
|                 return self.O | ||||
|             elif value == -3: | ||||
|                 return self.X | ||||
|  | ||||
|         # Check diagonals | ||||
|         diag = self.board[0][2] + self.board[1][1] + self.board[2][0] | ||||
|         if diag == 3: | ||||
|             return self.O | ||||
|         elif diag == -3: | ||||
|             return self.X | ||||
|  | ||||
|         diag = self.board[0][0] + self.board[1][1] + self.board[2][2] | ||||
|         if diag == 3: | ||||
|             return self.O | ||||
|         elif diag == -3: | ||||
|             return self.X | ||||
|  | ||||
|         # If we're here, we need to check if a tie was made | ||||
|         if all(i != 0 for row in self.board for i in row): | ||||
|             return self.Tie | ||||
|  | ||||
|         return None | ||||
|  | ||||
|  | ||||
| class TicTacToeBot(commands.Bot): | ||||
|     def __init__(self): | ||||
|         super().__init__(command_prefix=commands.when_mentioned_or('$')) | ||||
|  | ||||
|     async def on_ready(self): | ||||
|         print(f'Logged in as {self.user} (ID: {self.user.id})') | ||||
|         print('------') | ||||
|  | ||||
|  | ||||
| bot = TicTacToeBot() | ||||
|  | ||||
|  | ||||
| @bot.command() | ||||
| async def tic(ctx: commands.Context): | ||||
|     """Starts a tic-tac-toe game with yourself.""" | ||||
|     await ctx.send('Tic Tac Toe: X goes first', view=TicTacToe()) | ||||
|  | ||||
|  | ||||
| bot.run('token') | ||||
		Reference in New Issue
	
	Block a user