Add examples for how to use views
This commit is contained in:
parent
2beee8be14
commit
7386a971f8
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')
|
Loading…
x
Reference in New Issue
Block a user