Puede instalar la última versión de Pypi de la biblioteca haciendo:
$ pip install reactionmenu
O la versión de desarrollo:
$ pip install git+https://github.com/Defxult/reactionmenu
Intentos mínimos necesarios
bot = commands . Bot (..., intents = discord . Intents ( messages = True , guilds = True , reactions = True , members = True )) class reactionmenu.ReactionMenu(method: Union[Context, discord.Interaction], /, *, menu_type: MenuType, **kwargs)
Un ReactionMenu es un menú que utiliza emojis que son emojis de gremios personalizados o un emoji normal para controlar el proceso de paginación. Si no está buscando ninguna de las características elegantes y solo quiere algo simple, este es el que debe usar.
from reactionmenu import ReactionMenu , ReactionButtonEsta biblioteca viene con varios métodos y opciones para simplificar un menú de reacción de Discord. Una vez que haya importado las clases adecuadas, inicializará el constructor así:
menu = ReactionMenu ( method , menu_type = ReactionMenu . TypeEmbed )method ( Union[discord.ext.commands.Context, discord.Interaction] ) un objeto de contexto o interacciónmenu_type ( MenuType ) La configuración del menúReactionMenu.TypeEmbed , un menú de paginación de incrustación normalReactionMenu.TypeEmbedDynamic , un menú de paginación de incrustación con datos dinámicosReactionMenu.TypeText , un menú de paginación solo de texto| Nombre | Tipo | Valor predeterminado | Utilizado para | Información |
|---|---|---|---|---|
wrap_in_codeblock | str | None | ReactionMenu.TypeEmbedDynamic | El identificador ReactionMenu(ctx, ..., wrap_in_codeblock='py') lenguaje Discord CodeBlock para envolver sus datos en. |
custom_embed | discord.Embed | None | ReactionMenu.TypeEmbedDynamic | Incrustar el objeto para usar al agregar datos con ReactionMenu.add_row() . Utilizado para fines de estilo |
delete_on_timeout | bool | False | All menu types | Eliminar el menú cuando se desprende |
clear_reactions_after | bool | True | All menu types | Eliminar todas las reacciones después de que el menú salga de tiempo |
navigation_speed | str | ReactionMenu.NORMAL | All menu types | Establece si el usuario debe esperar a que el bot de eliminar la reacción sea eliminada antes de "cambiar" la página. Establecer la velocidad a ReactionMenu.FAST lo hace para que no haya necesidad de esperar (las reacciones no se eliminan en cada prensa) y pueden navegar por los largos menú más rápidamente |
only_roles | List[discord.Role] | None | All menu types | Si se establece, solo los miembros con cualquiera de los roles dados pueden controlar el menú. El propietario del menú siempre puede controlar el menú |
timeout | Union[int, float, None] | 60.0 | All menu types | El temporizador para cuando el menú sale a tiempo. No puede ser None sin tiempo de espera |
show_page_director | bool | True | All menu types | Se muestra en la parte inferior de cada página de incrustación. "Página 1/20" |
name | str | None | All menu types | Un nombre que puede configurar para el menú |
style | str | "Page $/&" | All menu types | Un estilo de director de página personalizado que puede seleccionar. "$" representa la página actual "y" representa la cantidad total de páginas. Ejemplo: ReactionMenu(ctx, ..., style='On $ out of &') |
all_can_click | bool | False | All menu types | Conjuntos Si todos pueden controlar cuando las páginas se 'giran' cuando se hacen clic en los botones |
delete_interactions | bool | True | All menu types | Elimine el mensaje de inmediato por el mensaje BOT y de respuesta del usuario cuando se le preguntó a qué página le gustaría ir cuando use ReactionButton.Type.GO_TO_PAGE |
rows_requested | int | None | ReactionMenu.TypeEmbedDynamic | La cantidad de información por ReactionMenu.add_row() que desea aplicar a cada página de incrustación |
remove_extra_emojis | bool | False | All menu types | Si True , todos los emojis (reacciones) agregados al mensaje de menú que no se agregaron originalmente al menú se eliminarán |
Dependiendo del menu_type , las páginas pueden ser un str , discord.Embed o una combinación de content y files (ejemplo a continuación)
menu_type es ReactionMenu.TypeEmbed , use incrustacionesmenu_type es ReactionMenu.TypeText (menú solo de texto) o ReactionMenu.TypeEmbedDynamic (menú de solo incrustación), use cadenas.ReactionMenu.add_page(embed: discord.Embed=MISSING, content: Optional[str]=None, files: Optional[Sequence[discord.File]]=None)ReactionMenu.add_pages(pages: Sequence[Union[discord.Embed, str]])ReactionMenu.add_row(data: str)ReactionMenu.remove_all_pages()ReactionMenu.clear_all_row_data()ReactionMenu.remove_page(page_number: int)ReactionMenu.set_main_pages(*embeds: Embed)ReactionMenu.set_last_pages(*embeds: Embed) # ReactionMenu.TypeEmbed
menu = ReactionMenu ( method , menu_type = ReactionMenu . TypeEmbed )
menu . add_page ( summer_embed )
menu . add_page ( winter_embed )
# ReactionMenu.TypeText
menu = ReactionMenu ( method , menu_type = ReactionMenu . TypeText )
menu . add_page ( content = 'Its so hot!' )
menu . add_page ( content = 'Its so cold!' ) Un menú TypeText es un menú de paginación basado en texto. No hay incrustaciones involucradas en el proceso de paginación, solo se usa texto plano.
Con v3.1.0+ , puede paginar con algo más que una simple incrustación o texto. Puede combinar texto, incrustaciones y archivos. Pero dependiendo del menu_type la combinación puede restringirse. Aquí hay un ejemplo de un menú con un menu_type de TypeEmbed que está apilado.
# You can use regular commands as well
@ bot . tree . command ( description = "These are stacked pages" , guild = discord . Object ( id = ...))
async def stacked ( interaction : discord . Interaction ):
menu = ReactionMenu ( interaction , menu_type = ReactionMenu . TypeEmbed )
menu . add_page ( discord . Embed ( title = "My Embed" ), content = "This content is stacked on top of a file" , files = [ discord . File ( "stacked.py" )])
menu . add_page ( discord . Embed ( title = "Hey Wumpos, can you say hi to the person reading this? ?" ))
menu . add_page ( discord . Embed ( title = "Hi, I'm Wumpos!" ), files = [ discord . File ( "wumpos.gif" )])
menu . add_button ( ReactionButton . back ())
menu . add_button ( ReactionButton . next ())
await menu . start () Dado que el menu_type está TypeEmbed , siempre debe haber una incrustación en cada página. Si el menu_type fue TypeText , las incrustaciones no están permitidas y se limitará a usar solo el parámetro files .
Se utiliza un menú dinámico cuando no sabe cuánta información se aplicará al menú. Por ejemplo, si solicitara información de una base de datos, esa información siempre puede cambiar. Usted consulta algo y puede recuperar 1.500 resultados, y el siguiente quizás solo 800. Un menú dinámico ata a toda esta información para usted y la agrega a una página de inserción por filas de datos. ReactionMenu.add_row() se usa mejor en algún tipo de Iterable donde todo se puede recorrer, pero solo agregue la cantidad de datos que desea a la página del menú.
Nota: En un menú dinámico, todos los datos agregados se colocan en la sección Descripción de una incrustación. Si elige usar un
custom_embed, todo el texto de la descripción se anulará con los datos que agregue
ReactionMenu.add_row(data: str)ReactionMenu.clear_all_row_data()ReactionMenu.set_main_pages(*embeds: Embed)ReactionMenu.set_last_pages(*embeds: Embed)rows_requested : la cantidad de filas que desea en cada página de incrustación antes de hacer una nueva páginaReactionMenu(..., rows_requested=5)custom_embed : una incrustación que ha creado para usar como páginas de incrustación. Usado para su estética de menúReactionMenu(..., custom_embed=red_embed)wrap_in_codeblock : el identificador de idioma al envolver sus datos en un CodeBlock de Discord.ReactionMenu(..., wrap_in_codeblock='py') menu = ReactionMenu ( ctx , menu_type = ReactionMenu . TypeEmbedDynamic , rows_requested = 5 )
for data in database . request ( 'SELECT * FROM customers' ):
menu . add_row ( data ) Puede eliminar todos los datos que ha agregado a un menú utilizando menu.clear_all_row_data()
Al usar un menú dinámico, las únicas páginas de incrustación que ve son de los datos que ha agregado. Pero si desea mostrar más páginas más que solo los datos, puede usar métodos ReactionMenu.set_main_pages() y ReactionMenu.set_last_pages() . Configuración de las páginas principales, las incrustaciones que configura serán las primeras incrustaciones que se muestran cuando comience el menú. Configuración de las últimas páginas son las últimas incrustaciones que se muestran
menu . set_main_pages ( welcome_embed , announcement_embed )
for data in get_information ():
menu . add_row ( data )
menu . set_last_pages ( additional_info_embed )
# NOTE: setting main/last pages can be set in any orderLos tipos de botones/botones se utilizan cuando desea agregar una reacción al menú que realiza una determinada función. Los botones y los tipos de botones funcionan juntos para lograr la acción deseada.
class reactionmenu.ReactionButton(*, emoji: str, linked_to: ButtonType, **kwargs)
emoji ( str ) el emoji que te gustaría usar como reacciónlinked_to ( ReactionButton.Type ) Cuando se presiona la reacción, esto es lo que determina lo que hará| Nombre | Tipo | Valor predeterminado | Utilizado para |
|---|---|---|---|
embed | discord.Embed | None | Cuando se presione la reacción, vaya a la incrustación especificada |
name | str | None | El nombre del botón |
details | Información a continuación | None | Asigna la función y sus argumentos llamar cuando se presiona un ReactionButton con ReactionButton.Type.CALLER |
event | ReactionButton.Event | None | Determine cuándo se debe eliminar un botón dependiendo de cuántas veces se ha presionado |
skip | ReactionButton.Skip | None | Establezca la acción y la cantidad de páginas para omitir cuando use un linked_to de ReactionButton.Type.SKIP . Por ejemplo, usando este tipo de botón, configurar la acción en "+" y la cantidad 3. Si está en la "página 1/20", presionar ese botón lo llevará a "Página 4/20" |
| Propiedad | Tipo de retorno | Información |
|---|---|---|
clicked_by | Set[discord.Member] | Los miembros que hicieron clic en el botón |
total_clicks | int | Cantidad de clics desde el botón |
last_clicked | Optional[datetime.datetime] | La hora en UTC para cuando se hizo clic en el botón por última vez |
menu | Optional[ReactionMenu] | El menú El botón está conectado al |
ReactionMenu.add_button(button: ReactionButton)ReactionMenu.remove_all_buttons()ReactionMenu.remove_button(button: ReactionButton)ReactionMenu.get_button(identity: Union[str, int], *, search_by='name')ReactionButton.set_caller_details(func: Callable[..., None], *args, **kwargs)| Tipo | Información |
|---|---|
ReactionButton.Type.NEXT_PAGE | Vaya a la página siguiente en la sesión del menú |
ReactionButton.Type.PREVIOUS_PAGE | Vaya a la página anterior en la sesión del menú |
ReactionButton.Type.GO_TO_FIRST_PAGE | Vaya a la primera página en la sesión del menú |
ReactionButton.Type.GO_TO_LAST_PAGE | Vaya a la última página en la sesión del menú |
ReactionButton.Type.GO_TO_PAGE | Le pide que escriba en la página a la que le gustaría ir |
ReactionButton.Type.END_SESSION | Detiene la sesión y elimina el mensaje del menú |
ReactionButton.Type.CUSTOM_EMBED | Utilizado por separado de los botones de navegación. Una vez presionado, vaya a la inserción especificada |
ReactionButton.Type.CALLER | Utilizado al especificar la función para llamar y sus argumentos cuando se presiona el botón |
ReactionButton.Type.SKIP | Se usa para paginar a través de varias páginas en un solo botón, presione |
Puede agregar botones (reacciones) al menú utilizando un ReactionButton . A continuación se presentan ejemplos sobre cómo usar cada ButtonType .
NOTA: Los buttones de reacción con
ReactionButton.Type.CALLERson un poco diferentes, por lo que hay una sección dedicada que explica cómo funcionan y cómo implementarlos a continuación
menu = ReactionMenu (...)
# first and last pages
fpb = ReactionButton ( emoji = '⏪' , linked_to = ReactionButton . Type . GO_TO_FIRST_PAGE )
lpb = ReactionButton ( emoji = '⏩' , linked_to = ReactionButton . Type . GO_TO_LAST_PAGE )
# go to page
gtpb = ReactionButton ( emoji = '?' , linked_to = ReactionButton . Type . GO_TO_PAGE )
# end session
esb = ReactionButton ( emoji = '⏹️' , linked_to = ReactionButton . Type . END_SESSION )
# custom embed
ceb = ReactionButton ( emoji = '?' , linked_to = ReactionButton . Type . CUSTOM_EMBED , embed = discord . Embed ( title = 'Hello' ))
# skip button
sb = ReactionButton ( emoji = '5️⃣' , linked_to = ReactionButton . Type . SKIP , skip = ReactionButton . Skip ( action = '+' , amount = 5 ))
menu . add_button ( fpb )
... Elimine todos los botones con menu.remove_all_buttons() . También puede eliminar un botón individual usando su nombre si lo tiene configurado, o el objeto de botón en sí con menu.remove_button()
ReactionButton.Type.CALLER Los botones se utilizan para implementar su propia funcionalidad en el menú. Tal vez desee agregar un botón que cree un canal de texto, envíe un mensaje o agregar algo a una base de datos, sea lo que sea. Para trabajar con ReactionButton.Type.CALLER , use el método de clase a continuación.
ReactionButton.set_caller_details(func: Callable[..., None], *args, **kwargs) Este método de clase se utiliza para configurar una función y sus argumentos que luego se llaman cuando se presiona el botón. El constructor ReactionButton tiene los details de Kwarg, y eso es lo que usará con .set_caller_details() para asignar los valores necesarios. Algunos ejemplos están a continuación sobre cómo implementar correctamente ReactionButton.Type.CALLER
@ bot . command ()
async def user ( ctx , name , * , message ):
await ctx . send ( f"Hi { name } ! { message } . We're glad you're here!" )
def car ( year , make , model ):
print ( f"I have a { year } { make } { model } " )
ub = ReactionButton ( emoji = '' , linked_to = ReactionButton . Type . CALLER , details = ReactionButton . set_caller_details ( user , ctx , 'Defxult' , message = 'Welcome to the server' ))
cb = ReactionButton ( emoji = '?' , linked_to = ReactionButton . Type . CALLER , details = ReactionButton . set_caller_details ( car , 2021 , 'Ford' , 'Mustang' ))Nota: La función en la que se encuentra no debe devolver nada. Llamar a las funciones con
ReactionButton.Type.CALLERno almacena ni maneja nada devuelto por esa función
La clase ReactionButton viene con un conjunto de métodos de fábrica (métodos de clase) que devuelve un ReactionButton con parámetros establecidos de acuerdo con su linked_to .
ReactionButton.back()emoji : "linked_to : ReactionButton.Type.PREVIOUS_PAGEReactionButton.next()emoji : "linked_to : ReactionButton.Type.NEXT_PAGEReactionButton.go_to_first_page()emoji : "⏪"linked_to : ReactionButton.Type.GO_TO_FIRST_PAGEReactionButton.go_to_last_page()emoji : "⏩"linked_to : ReactionButton.Type.GO_TO_LAST_PAGEReactionButton.go_to_page()emoji : "?"linked_to : ReactionButton.Type.GO_TO_PAGEReactionButton.end_session()emoji : "⏹️"linked_to : ReactionButton.Type.END_SESSIONReactionButton.all()list de ReactionButton en el siguiente orden.go_to_first_page() .back() .next() .go_to_last_page() .go_to_page() .end_session()ReactionButton.generate_skip(emoji: str, action: str, amount: int)emoji : <emoji>linked_to : ReactionButton.Type.SKIPskip : ReactionButton.Skip(<action>, <amount>)Si lo desea, puede limitar la cantidad de menús de reacción que pueden estar activos al mismo tiempo por "gremio", "miembro" o "canal"
ReactionMenu.set_sessions_limit(limit: int, per='guild', message='Too many active menus. Wait for other menus to be finished.')ReactionMenu.remove_limit()Ejemplo:
@ bot . command ()
async def limit ( ctx ):
ReactionMenu . set_sessions_limit ( 3 , per = 'member' , message = 'Sessions are limited to 3 per member' )Con el ejemplo anterior, solo 3 menús pueden estar activos a la vez para cada miembro, y si intentan crear más antes de que terminen sus otros menú, recibirán un mensaje de error que dice "Las sesiones están limitadas a 3 por miembro".
Puede establecer un ReactionButton para eliminar cuando se ha presionado una cierta cantidad de veces
class ReactionButton.Event(event_type: str, value: int)
event_type ( str ) la acción a tomar. La única opción disponible es "eliminar"value ( int ) la cantidad establecida para el evento especificado. Debe ser> = 1. Si el valor es <= 0, se establece implícitamente en 1Ejemplo:
menu = ReactionMenu ( ctx , ...)
# remove a button after 10 clicks
button = ReactionButton (..., event = ReactionButton . Event ( 'remove' , 10 ))
menu . add_button ( button )Nota: No es ideal para botones con un
linked_todeReactionButton.Type.END_SESSION
Los relés del menú son funciones que se llaman cada vez que se presiona un botón que aparece en un menú. Se considera como una extensión de un ReactionButton con un linked_to de ReactionButton.Type.CALLER . A diferencia de los botones de llamadas que no proporcionan detalles sobre las interacciones en el menú, los relés sí.
ReactionMenu.set_relay(func: Callable[[NamedTuple], None], *, only: Optional[List[ReactionButton]]=None)ReactionMenu.remove_relay() Al crear una función para su relé, esa función debe contener un solo argumento posicional. Cuando se presiona un botón, se pasa un objeto RelayPayload (una tupla llamada) a esa función. Los atributos de RelayPayload son:
member ( discord.Member ) La persona que presionó el botónbutton ( ReactionButton ) El botón que se presionóEjemplo:
async def enter_giveaway ( payload ):
member = payload . member
channel = payload . button . menu . message . channel
await channel . send ( f" { member . mention } , you've entered the giveaway!" )
menu = ReactionMenu ( ctx , ...)
menu . set_relay ( enter_giveaway ) El método set_relay viene con el only parámetro. Si ese parámetro es None , todos los botones que se presionan serán transmitidos. Puede proporcionar una list de botones a ese parámetro, por lo que solo se transmitirán las presiones del botón de los botones especificados.
def example ( payload ):
...
menu = ReactionMenu ( ctx , ...)
back_button = ReactionButton . back ()
next_button = ReactionButton . next ()
menu . set_relay ( example , only = [ back_button ])await ReactionMenu.start(*, send_to=None, reply=False)await ReactionMenu.stop(*, delete_menu_message=False, clear_reactions=False) Al comenzar el menú, tiene la opción de enviar el menú a un determinado canal. El parámetro send_to es el canal al que le gustaría enviar el menú. Puede establecer send_to como el nombre del canal ( str ), ID de canal ( int ) o objeto de canal ( discord.TextChannel / discord.Thread ). Ejemplo:
menu = ReactionMenu (...)
# channel name
await menu . start ( send_to = 'bot-commands' )
# channel ID
await menu . start ( send_to = 1234567890123456 )
# channel object
channel = guild . get_channel ( 1234567890123456 )
await menu . start ( send_to = channel )
# there's no need to specify send_to unless you want the menu to be sent to a different channel
# from the one you're sending the initial message/using the command in. the menu can be started
# in the current channel by omitting the send_to parameter
await menu . start ()Nota:
send_tono es válido si se inició un menú en DM's
Aquí hay una implementación básica de ReactionMenu que puede copiar y pegar para una demostración rápida.
import asyncio
import discord
from discord . ext import commands
from reactionmenu import ReactionMenu , ReactionButton
bot = commands . Bot ( command_prefix = '!' , intents = discord . Intents . all ())
async def start_bot ():
async with bot :
await bot . start ( '...' )
@ bot . command ()
async def example ( ctx ):
menu = ReactionMenu ( ctx , menu_type = ReactionMenu . TypeEmbed )
for member in ctx . guild . members :
if member . avatar :
embed = discord . Embed ( description = f'Joined { member . joined_at . strftime ( "%b. %d, %Y" ) } ' )
embed . set_author ( name = member . name , icon_url = member . avatar . url )
menu . add_page ( embed )
menu . add_button ( ReactionButton . back ())
menu . add_button ( ReactionButton . next ())
menu . add_button ( ReactionButton . end_session ())
await menu . start ()
asyncio . run ( start_bot ()) class reactionmenu.ViewMenu(method: Union[Context, discord.Interaction], /, *, menu_type: MenuType, **kwargs)
Un ViewMenu es un menú que utiliza la función de botones Discords. Con los botones, puede habilitarlos y deshabilitarlos, establecer un cierto color para ellos con emojis, tener botones que envíen mensajes ocultos y agregue hipervínculos. Esta biblioteca ofrece una gama más amplia de funcionalidades, como quién presionó el botón, cuántas veces fue presionada y más. Utiliza vistas ( discord.ui.View ) para implementar la funcionalidad de los botones, pero utiliza algunos de sus propios métodos para simplificar un menú de paginación de botones.
from reactionmenu import ViewMenu , ViewButtonmethod ( Union[discord.ext.commands.Context, discord.Interaction] ) un objeto de contexto o interacciónmenu_type ( MenuType ) La configuración del menúViewMenu.TypeEmbed , un menú de paginación de incrustación normalViewMenu.TypeEmbedDynamic , un menú de paginación de incrustación con datos dinámicosViewMenu.TypeText , un menú de paginación solo de texto| Nombre | Tipo | Valor predeterminado | Utilizado para | Información |
|---|---|---|---|---|
wrap_in_codeblock | str | None | ViewMenu.TypeEmbedDynamic | El identificador ViewMenu(ctx, ..., wrap_in_codeblock='py') lenguaje Discord CodeBlock para envolver sus datos. |
custom_embed | discord.Embed | None | ViewMenu.TypeEmbedDynamic | Incrustar el objeto para usar al agregar datos con ViewMenu.add_row() . Utilizado para fines de estilo |
delete_on_timeout | bool | False | All menu types | Eliminar el menú cuando se desprende |
disable_items_on_timeout | bool | True | All menu types | Deshabilite los elementos en el menú cuando el menú salga a la hora |
remove_items_on_timeout | bool | False | All menu types | Elimine los elementos del menú cuando se desprende el menú |
only_roles | List[discord.Role] | None | All menu types | Si se establece, solo los miembros con cualquiera de los roles dados pueden controlar el menú. El propietario del menú siempre puede controlar el menú |
timeout | Union[int, float, None] | 60.0 | All menu types | El temporizador para cuando el menú sale a tiempo. No puede ser None sin tiempo de espera |
show_page_director | bool | True | All menu types | Se muestra en la parte inferior de cada página de incrustación. "Página 1/20" |
name | str | None | All menu types | Un nombre que puede configurar para el menú |
style | str | "Page $/&" | All menu types | Un estilo de director de página personalizado que puede seleccionar. "$" representa la página actual "y" representa la cantidad total de páginas. Ejemplo: ViewMenu(ctx, ..., style='On $ out of &') |
all_can_click | bool | False | All menu types | Conjuntos Si todos pueden controlar cuando las páginas se 'giran' cuando se hacen clic en los botones |
delete_interactions | bool | True | All menu types | Elimine el mensaje de inmediato por el mensaje BOT y de respuesta del usuario cuando se le preguntó a qué página le gustaría ir cuando use ViewButton.ID_GO_TO_PAGE |
rows_requested | int | None | ViewMenu.TypeEmbedDynamic | La cantidad de información por ViewMenu.add_row() que desea aplicar a cada página de inserción |
Dependiendo del menu_type , las páginas pueden ser un str , discord.Embed o una combinación de content o files (ejemplo a continuación)
menu_type es ViewMenu.TypeEmbed , use Incrustosmenu_type es ViewMenu.TypeText (menú solo de texto) o ViewMenu.TypeEmbedDynamic (menú de Insquitir solo), use cadenas.ViewMenu.add_page(embed: discord.Embed=MISSING, content: Optional[str]=None, files: Optional[Sequence[discord.File]]=None)ViewMenu.add_pages(pages: Sequence[Union[discord.Embed, str]])ViewMenu.add_row(data: str)ViewMenu.remove_all_pages()ViewMenu.clear_all_row_data()ViewMenu.remove_page(page_number: int)ViewMenu.set_main_pages(*embeds: Embed)ViewMenu.set_last_pages(*embeds: Embed) # ViewMenu.TypeEmbed
menu = ViewMenu ( method , menu_type = ViewMenu . TypeEmbed )
menu . add_page ( summer_embed )
menu . add_page ( winter_embed )
# ViewMenu.TypeText
menu = ViewMenu ( method , menu_type = ViewMenu . TypeText )
menu . add_page ( content = 'Its so hot!' )
menu . add_page ( content = 'Its so cold!' ) Un menú TypeText es un menú de paginación basado en texto. No hay incrustaciones involucradas en el proceso de paginación, solo se usa texto plano.
Con v3.1.0+ , puede paginar con algo más que una simple incrustación o texto. Puede combinar texto, incrustaciones y archivos. Pero dependiendo del menu_type la combinación puede restringirse. Aquí hay un ejemplo de un menú con un menu_type de TypeEmbed que está apilado.
# You can use regular commands as well
@ bot . tree . command ( description = "These are stacked pages" , guild = discord . Object ( id = ...))
async def stacked ( interaction : discord . Interaction ):
menu = ViewMenu ( interaction , menu_type = ViewMenu . TypeEmbed )
menu . add_page ( discord . Embed ( title = "My Embed" ), content = "This content is stacked on top of a file" , files = [ discord . File ( "stacked.py" )])
menu . add_page ( discord . Embed ( title = "Hey Wumpos, can you say hi to the person reading this? ?" ))
menu . add_page ( discord . Embed ( title = "Hi, I'm Wumpos!" ), files = [ discord . File ( "wumpos.gif" )])
menu . add_button ( ViewButton . back ())
menu . add_button ( ViewButton . next ())
await menu . start () Dado que el menu_type está TypeEmbed , siempre debe haber una incrustación en cada página. Si el menu_type fue TypeText , las incrustaciones no están permitidas y se limitará a usar solo el parámetro files .
Se utiliza un menú dinámico cuando no sabe cuánta información se aplicará al menú. Por ejemplo, si solicitara información de una base de datos, esa información siempre puede cambiar. Usted consulta algo y puede recuperar 1.500 resultados, y el siguiente quizás solo 800. Un menú dinámico ata a toda esta información para usted y la agrega a una página de inserción por filas de datos. ViewMenu.add_row() se usa mejor en algún tipo de Iterable donde todo se puede recorrer, pero solo agregue la cantidad de datos que desea a la página del menú.
Nota: En un menú dinámico, todos los datos agregados se colocan en la sección Descripción de una incrustación. Si elige usar un
custom_embed, todo el texto de la descripción se anulará con los datos que agregue
ViewMenu.add_row(data: str)ViewMenu.clear_all_row_data()ViewMenu.set_main_pages(*embeds: Embed)ViewMenu.set_last_pages(*embeds: Embed)rows_requested : la cantidad de filas que desea en cada página de incrustación antes de hacer una nueva páginaViewMenu(..., rows_requested=5)custom_embed : una incrustación que ha creado para usar como páginas de incrustación. Usado para su estética de menúViewMenu(..., custom_embed=red_embed)wrap_in_codeblock : el identificador de idioma al envolver sus datos en un CodeBlock de Discord.ViewMenu(..., wrap_in_codeblock='py') menu = ViewMenu ( ctx , menu_type = ViewMenu . TypeEmbedDynamic , rows_requested = 5 )
for data in database . request ( 'SELECT * FROM customers' ):
menu . add_row ( data ) Puede eliminar todos los datos que ha agregado a un menú utilizando menu.clear_all_row_data()
Al usar un menú dinámico, las únicas páginas de incrustación que ve son de los datos que ha agregado. Pero si desea mostrar más páginas más que solo los datos, puede usar métodos ViewMenu.set_main_pages() y ViewMenu.set_last_pages() . Configuración de las páginas principales, las incrustaciones que configura serán las primeras incrustaciones que se muestran cuando comience el menú. Configuración de las últimas páginas son las últimas incrustaciones que se muestran
menu . set_main_pages ( welcome_embed , announcement_embed )
for data in get_information ():
menu . add_row ( data )
menu . set_last_pages ( additional_info_embed )
# NOTE: setting main/last pages can be set in any orderLos botones son lo que usa para interactuar con el menú. A diferencia de las reacciones, se ven más limpios, proporcionan menos problemas de límite de velocidad y ofrecen más en términos de interacciones. Habilitar y deshabilitar los botones, usar Hyperlinks de Markdown en sus mensajes e incluso enviar mensajes ocultos.
ViewMenu.add_button(button: ViewButton)ViewMenu.disable_all_buttons()ViewMenu.disable_button(button: ViewButton)ViewMenu.enable_all_buttons()ViewMenu.enable_button(button: ViewButton)ViewMenu.get_button(identity: str, *, search_by='label')ViewMenu.remove_all_buttons()ViewMenu.remove_button(button: ViewButton)await ViewMenu.refresh_menu_items() class reactionmenu.ViewButton(*, style=discord.ButtonStyle.secondary, label=None, disabled=False, custom_id=None, url=None, emoji=None, followup=None, event=None, **kwargs)
Un ViewButton es una clase que representa el botón Discord. Es una subclase de discord.ui.Button .
Las siguientes son las reglas establecidas por Discord para botones:
custom_id y no pueden tener una urlurl y no pueden tener un custom_idstyle ( discord.ButtonStyle ) el estilo de botónlabel ( str ) el texto en el botóncustom_id ( str ) una identificación para determinar qué acción debe tomar ese botón. IDS disponibles:ViewButton.ID_NEXT_PAGEViewButton.ID_PREVIOUS_PAGEViewButton.ID_GO_TO_FIRST_PAGEViewButton.ID_GO_TO_LAST_PAGEViewButton.ID_GO_TO_PAGEViewButton.ID_END_SESSIONViewButton.ID_CALLERViewButton.ID_SEND_MESSAGEViewButton.ID_CUSTOM_EMBEDViewButton.ID_SKIPemoji ( Union[str, discord.PartialEmoji] ) emoji utilizado para el botónViewButton(..., emoji='?')ViewButton(..., emoji='<:miscTwitter:705423192818450453>')ViewButton(..., emoji='U000027a1')ViewButton(..., emoji='N{winking face}')url ( str ) URL para un botón con estilo discord.ButtonStyle.linkdisabled ( bool ) Si el botón se deshabilitefollowup ( ViewButton.Followup ) El mensaje enviado después del botón se presiona. Solo disponible para botones que tienen un custom_id de ViewButton.ID_CALLER o ViewButton.ID_SEND_MESSAGE . ViewButton.Followup es una clase que tiene parámetros similares a discord.abc.Messageable.send() , y se usa para controlar si un mensaje es efímero, contiene un archivo, incrustación, TTS, etc. ...event ( ViewButton.Event ) Establezca un botón para deshabilitar o eliminar cuando se haya presionado una cierta cantidad de veces | Nombre | Tipo | Valor predeterminado | Utilizado para |
|---|---|---|---|
name | str | None | El nombre del botón |
skip | ViewButton.Skip | None | Establezca la acción y la cantidad de páginas para omitir cuando use un custom_id de ViewButton.ID_SKIP . Por ejemplo, configurar la acción en "+" y la cantidad 3. Si está en la "página 1/20", presionar ese botón lo llevará a "Página 4/20" |
persist | bool | False | Evita que los botones de enlace se desactiven/se eliminen cuando el menú salga a tiempo o se detiene para que puedan permanecer haciendo clic en |
| Propiedad | Tipo de retorno | Información |
|---|---|---|
clicked_by | Set[discord.Member] | Los miembros que hicieron clic en el botón |
total_clicks | int | Cantidad de clics desde el botón |
last_clicked | Optional[datetime.datetime] | La hora en UTC para cuando se hizo clic en el botón por última vez |
menu | Optional[ViewMenu] | El menú El botón está conectado al |
from reactionmenu import ViewMenu , ViewButton
menu = ViewMenu ( ctx , menu_type = ViewMenu . TypeEmbed )
# Link button
link_button = ViewButton ( style = discord . ButtonStyle . link , emoji = '?' , label = 'Link to Google' , url = 'https://google.com' )
menu . add_button ( link_button )
# Skip button
skip = ViewButton ( style = discord . ButtonStyle . primary , label = '+5' , custom_id = ViewButton . ID_SKIP , skip = ViewButton . Skip ( action = '+' , amount = 5 ))
menu . add_button ( skip )
# ViewButton.ID_PREVIOUS_PAGE
back_button = ViewButton ( style = discord . ButtonStyle . primary , label = 'Back' , custom_id = ViewButton . ID_PREVIOUS_PAGE )
menu . add_button ( back_button )
# ViewButton.ID_NEXT_PAGE
next_button = ViewButton ( style = discord . ButtonStyle . secondary , label = 'Next' , custom_id = ViewButton . ID_NEXT_PAGE )
menu . add_button ( next_button )
# All other ViewButton are created the same way as the last 2 EXCEPT
# 1 - ViewButton.ID_CALLER
# 2 - ViewButton.ID_SEND_MESSAGE
# 3 - ViewButton.ID_CUSTOM_EMBED
# ViewButton.ID_CALLER
def say_hello ( name : str ):
print ( 'Hello' , name )
call_followup = ViewButton . Followup ( details = ViewButton . Followup . set_caller_details ( say_hello , 'John' ))
menu . add_button ( ViewButton ( label = 'Say hi' , custom_id = ViewButton . ID_CALLER , followup = call_followup ))
# ViewButton.ID_SEND_MESSAGE
msg_followup = ViewButton . Followup ( 'This message is hidden!' , ephemeral = True )
menu . add_button ( ViewButton ( style = discord . ButtonStyle . green , label = 'Message' , custom_id = ViewButton . ID_SEND_MESSAGE , followup = msg_followup ))
# ViewButton.ID_CUSTOM_EMBED
custom_embed_button = ViewButton ( style = discord . ButtonStyle . blurple , label = 'Social Media Info' , custom_id = ViewButton . ID_CUSTOM_EMBED , followup = ViewButton . Followup ( embed = discord . Embed (...)))Nota: Cuando se trata de botones con un
custom_iddeViewButton.ID_CALLER,ViewButton.ID_SEND_MESSAGE,ViewButton.ID_CUSTOM_EMBEDo Botones de enlace, puede agregar tantos como desee siempre que en total sus 25 botones o menos. Para todas las demás ID de botón, cada menú solo puede tener uno.
Se utilizan seleccionados cuando desea clasificar la información en su menú. Selecciona solo se puede usar cuando el menú menu_type está TypeEmbed . Debe tener en cuenta que las limitaciones de discordia en cuántos elementos de interfaz de usuario de menú (filas) se pueden aplicar a cada mensaje.
Page.from_embeds(embeds: Sequence[Embed])ViewMenu.add_select(select: ViewSelect)ViewMenu.remove_select(select: ViewSelect)ViewMenu.remove_all_selects()ViewMenu.disable_select(select: ViewSelect)ViewMenu.disable_all_selects()ViewMenu.enable_select(select: ViewSelect)ViewMenu.enable_all_selects()ViewMenu.get_select(title: Union[str, None])Ejemplo:
from reactionmenu import ViewMenu , ViewSelect , Page
menu = ViewMenu ( ctx , menu_type = ViewMenu . TypeEmbed )
menu . add_page ( discord . Embed ( title = "A showcase of console video games" , color = discord . Color . blurple ()))
menu . add_select ( ViewSelect ( title = "Console Video Games" , options = {
# NOTE: The discord.SelectOption parameter "default" cannot be set to True
discord . SelectOption ( label = "PlayStation" , emoji = "<:PlayStation:549638412538478602>" ) : [
Page ( embed = discord . Embed ( title = "Ratchet & Clank" , description = ..., color = discord . Color . yellow ()). set_image ( url = ...)),
Page ( embed = discord . Embed ( title = "God of War" , description = ..., color = discord . Color . blue ()). set_image ( url = ...))
],
discord . SelectOption ( label = "Xbox" , emoji = "<:Xbox:501880493285834752>" ) : [
Page ( embed = discord . Embed ( title = "Halo Infinite" , description = ..., color = discord . Color . green ()). set_image ( url = ...)),
Page ( embed = discord . Embed ( title = "Gears of War 4" , description = ..., color = discord . Color . red ()). set_image ( url = ...))
]
}))
menu . add_button ( ViewButton . back ())
menu . add_button ( ViewButton . next ())
await menu . start ()Puede usar este tipo de selección cuando desea usar la interfaz de usuario para seleccionar una página para ir.
ViewMenu.add_go_to_select(goto: ViewSelect.GoTo)ViewMenu.enable_go_to_select(goto: ViewSelect.GoTo)ViewMenu.enable_all_go_to_selects()ViewMenu.disable_go_to_select(goto: ViewSelect.GoTo)ViewMenu.disable_all_go_to_selects()ViewMenu.remove_go_to_select(goto: ViewSelect.GoTo)ViewMenu.remove_all_go_to_selects() El parámetro page_numbers para ViewSelect.GoTo se puede usar con 3 tipos diferentes
List[int] si se establece en una lista de enteros, esos valores especificados son las únicas opciones disponibles cuando se hace clic en Selectpage_numbers=[1, 5, 10]Dict[int, Union[str, discord.Emoji, discord.PartialEmoji]] Puede usar este tipo si desea utilizar emojis en su selecciónpage_numbers={1 : "?️", 2 : ""}ellipsis Puede establecer un elipsis literal para que la biblioteca asigne automáticamente todos los números de página a la cantidad de páginas que ha agregado al menú. Esto puede ser útil si tienes 25 páginas o menospage_numbers=...Nota : Configurar el parámetro
page_numbersen un ellipsis (...) solo funciona según lo previsto si ha agregado la selección de IR a
@ bot . command ()
async def navigate ( ctx ):
menu = ViewMenu ( ctx , menu_type = ViewMenu . TypeEmbed )
menu . add_page ( discord . Embed ( title = "Twitter" ). set_image ( url = "..." ))
menu . add_page ( discord . Embed ( title = "YouTube" ). set_image ( url = "..." ))
menu . add_page ( discord . Embed ( title = "Discord" ). set_image ( url = "..." ))
# ...
menu . add_go_to_select ( ViewSelect . GoTo ( title = "Go to page..." , page_numbers = ...))
menu . add_button ( ViewButton . back ())
menu . add_button ( ViewButton . next ())
await menu . start ()await ViewMenu.refresh_menu_items()await ViewMenu.update(*, new_pages: Union[List[Union[Embed, str]], None], new_buttons: Union[List[ViewButton], None]) Cuando se ejecuta el menú, puede actualizar las páginas o botones en el menú. Usando ViewMenu.update() , puede reemplazar las páginas y los botones. Usar ViewMenu.refresh_menu_items() actualiza los botones que ha cambiado.
@ bot . command ()
async def menu ( ctx ):
menu = ViewMenu (..., name = 'test' )
link_button = ViewButton (..., label = 'Link' )
menu . add_button ( link_button )
menu . add_page (...)
await menu . start ()
@ bot . command ()
async def disable ( ctx ):
menu = ViewMenu . get_session ( 'test' )
link_button = menu [ 0 ]. get_button ( 'Link' , search_by = 'label' )
menu . disable_button ( link_button )
await menu . refresh_menu_items () Si los botones no se actualizan con ViewMenu.refresh_menu_items() , el menú no se actualizará al cambiar un botón.
Método ViewMenu.update(...) se usa cuando desea reemplazar todos o algunos de los botones en el menú.
menu = ViewMenu (...)
# in a different .command()
await menu . update ( new_pages = [ hello_embed , goodbye_embed ], new_buttons = [ link_button , next_button ])Nota : Cuando se usa
ViewMenu.update(...), no es necesario usarViewMenu.refresh_menu_items()porque se actualizan durante la llamada de actualización.
La clase ViewButton viene con un conjunto de métodos de fábrica (métodos de clase) que devuelve un ViewButton con parámetros establecidos de acuerdo con sus botones de enlace custom_id (excluyendo).
ViewButton.link(label: str, url: str)style : discord.ButtonStyle.linklabel : <label>url : <url>ViewButton.back()style : discord.ButtonStyle.graylabel : "Volver"custom_id : ViewButton.ID_PREVIOUS_PAGEViewButton.next()style : discord.ButtonStyle.graylabel : "Siguiente"custom_id : ViewButton.ID_NEXT_PAGEViewButton.go_to_first_page()style : discord.ButtonStyle.graylabel : "Primera página"custom_id : ViewButton.ID_GO_TO_FIRST_PAGEViewButton.go_to_last_page()style : discord.ButtonStyle.graylabel : "Última página"custom_id : ViewButton.ID_GO_TO_LAST_PAGEViewButton.go_to_page()style : discord.ButtonStyle.graylabel : "Selección de página"custom_id : ViewButton.ID_GO_TO_PAGEViewButton.end_session()discord.ButtonStyle.grayViewButton.ID_END_SESSIONViewButton.all()list de ViewButton en el siguiente orden.go_to_first_page() .back() .next() .go_to_last_page() .go_to_page() .end_session()ViewButton.all_with_emojis()list de ViewButton con sus parámetros emoji ya establecidos en el siguiente orden.go_to_first_page() .back() .next() .go_to_last_page() .go_to_page() .end_session()ViewButton.generate_skip(label: str, action: str, amount: int)style : discord.ButtonStyle.graylabel : <label>custom_id : ViewButton.ID_SKIPskip : ViewButton.Skip(<action>, <amount>) menu = ViewMenu ( ctx , ...)
menu . add_page (...)
menu . add_page (...)
menu . add_button ( ViewButton . back ())
menu . add_button ( ViewButton . next ())
await menu . start () Puede establecer un ViewButton para deshabilitar o eliminar cuando se ha presionado una cierta cantidad de veces
class ViewButton.Event(event_type: str, value: int)
event_type ( str ) la acción a tomar. Puede ser "deshabilitar" o "eliminar"value ( int ) la cantidad establecida para el evento especificado. Debe ser> = 1. Si el valor es <= 0, se establece implícitamente en 1Ejemplo:
menu = ViewMenu ( ctx , ...)
# disable a button after 5 clicks
button_1 = ViewButton (..., event = ViewButton . Event ( 'disable' , 5 ))
menu . add_button ( button_1 )
# remove a button after 10 clicks
button_2 = ViewButton (..., event = ViewButton . Event ( 'remove' , 10 ))
menu . add_button ( button_2 )Nota: No es válido para los botones de enlace. Tampoco es ideal para botones con un
custom_iddeViewButton.ID_END_SESSION
Los relés del menú son funciones que se llaman cada vez que se presiona un botón que aparece en un menú. Se considera como una extensión de un ViewButton con una ID de ViewButton.ID_CALLER . A diferencia de los botones de llamadas que no proporcionan detalles sobre las interacciones en el menú, los relés sí.
ViewMenu.set_relay(func: Callable[[NamedTuple], None], *, only: Optional[List[ViewButton]]=None)ViewMenu.remove_relay() Al crear una función para su relé, esa función debe contener un solo argumento posicional. Cuando se presiona un botón, se pasa un objeto RelayPayload (una tupla llamada) a esa función. Los atributos de RelayPayload son:
member ( discord.Member ) La persona que presionó el botónbutton ( ViewButton ) El botón que se presionóEjemplo:
async def enter_giveaway ( payload ):
member = payload . member
channel = payload . button . menu . message . channel
await channel . send ( f" { member . mention } , you've entered the giveaway!" )
menu = ViewMenu ( ctx , ...)
menu . set_relay ( enter_giveaway ) El método set_relay viene con el only parámetro. Si ese parámetro es None , todos los botones que se presionan se transmitirán (excepto los botones de enlace porque no envían eventos de interacción). Puede proporcionar una list de botones a ese parámetro, por lo que solo se transmitirán las presiones del botón de los botones especificados.
def example ( payload ):
...
menu = ViewMenu ( ctx , ...)
back_button = ViewButton . back ()
next_button = ViewButton . next ()
menu . set_relay ( example , only = [ back_button ])await ViewMenu.start(*, send_to=None, reply=False)await ViewMenu.stop(*, delete_menu_message=False, remove_buttons=False, disable_buttons=False) Al comenzar el menú, tiene la opción de enviar el menú a un determinado canal. El parámetro send_to es el canal al que le gustaría enviar el menú. Puede establecer send_to como el nombre del canal ( str ), ID de canal ( int ) o objeto de canal ( discord.TextChannel / discord.Thread ). Ejemplo:
menu = ViewMenu (...)
# channel name
await menu . start ( send_to = 'bot-commands' )
# channel ID
await menu . start ( send_to = 1234567890123456 )
# channel object
channel = guild . get_channel ( 1234567890123456 )
await menu . start ( send_to = channel )
# there's no need to specify send_to unless you want the menu to be sent to a different channel
# from the one you're sending the initial message/using the command in. the menu can be started
# in the current channel by omitting the send_to parameter
await menu . start ()Nota:
send_tono es válido si se inició un menú en DM's
Solo hay una opción disponible al detener el menú. Si tiene múltiples parámetros como True , solo uno se ejecutará
delete_menu_message > disable_buttonsdisable_buttons > remove_buttons Aquí hay una implementación básica de ViewMenu que puede copiar y pegar para una demostración rápida.
import asyncio
import discord
from discord . ext import commands
from reactionmenu import ViewMenu , ViewButton
bot = commands . Bot ( command_prefix = '!' , intents = discord . Intents . all ())
async def start_bot ():
async with bot :
await bot . start ( '...' )
@ bot . command ()
async def example ( ctx ):
menu = ViewMenu ( ctx , menu_type = ViewMenu . TypeEmbed )
for member in ctx . guild . members :
if member . avatar :
embed = discord . Embed ( description = f'Joined { member . joined_at . strftime ( "%b. %d, %Y" ) } ' )
embed . set_author ( name = member . name , icon_url = member . avatar . url )
menu . add_page ( embed )
menu . add_button ( ViewButton . back ())
menu . add_button ( ViewButton . next ())
menu . add_button ( ViewButton . end_session ())
await menu . start ()
asyncio . run ( start_bot ())