Você pode instalar a versão mais recente da Biblioteca Pypi fazendo:
$ pip install reactionmenu
Ou a versão de desenvolvimento:
$ pip install git+https://github.com/Defxult/reactionmenu
Intenções mínimas necessárias
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)
Um ReactionMenu é um menu que usa emojis que são emojis personalizados da guilda ou um emoji normal para controlar o processo de paginação. Se você não está procurando nenhum dos recursos sofisticados e só quer algo simples, este é o único a usar.
from reactionmenu import ReactionMenu , ReactionButtonEsta biblioteca vem com vários métodos e opções para simplificar um menu de reação de discórdia. Depois de importar as classes adequadas, você inicializará o construtor assim:
menu = ReactionMenu ( method , menu_type = ReactionMenu . TypeEmbed )method ( Union[discord.ext.commands.Context, discord.Interaction] ) Um contexto ou objeto de interaçãomenu_type ( MenuType ) A configuração do menuReactionMenu.TypeEmbed , um menu de paginação de incorporação normalReactionMenu.TypeEmbedDynamic , um menu de paginação incorporado com dados dinâmicosReactionMenu.TypeText , um menu de paginação apenas em texto| Nome | Tipo | Valor padrão | Usado para | Informações |
|---|---|---|---|---|
wrap_in_codeblock | str | None | ReactionMenu.TypeEmbedDynamic | O identificador de idioma do Discord CodeBlock para envolver seus dados. Exemplo: ReactionMenu(ctx, ..., wrap_in_codeblock='py') |
custom_embed | discord.Embed | None | ReactionMenu.TypeEmbedDynamic | Objeto incorporado a ser usado ao adicionar dados com ReactionMenu.add_row() . Usado para fins de estilo |
delete_on_timeout | bool | False | All menu types | Exclua o menu quando estiver |
clear_reactions_after | bool | True | All menu types | Exclua todas as reações após os tempos de menu |
navigation_speed | str | ReactionMenu.NORMAL | All menu types | Define se o usuário precisar aguardar a remoção da reação pelo bot antes de "girar" a página. Definir a velocidade para ReactionMenu.FAST |
only_roles | List[discord.Role] | None | All menu types | Se definido, apenas os membros com qualquer uma das funções fornecidas podem controlar o menu. O proprietário do menu sempre pode controlar o menu |
timeout | Union[int, float, None] | 60.0 | All menu types | O temporizador para quando o menu estiver fora. Pode ser None sem tempo limite |
show_page_director | bool | True | All menu types | Mostrado na parte inferior de cada página de incorporação. "Página 1/20" |
name | str | None | All menu types | Um nome que você pode definir para o menu |
style | str | "Page $/&" | All menu types | Um estilo de diretor de página personalizado que você pode selecionar. "$" representa a página atual "e" representa a quantidade total de páginas. Exemplo: ReactionMenu(ctx, ..., style='On $ out of &') |
all_can_click | bool | False | All menu types | Conjuntos se todos tiverem permissão para controlar quando as páginas são 'giradas' quando os botões são clicados |
delete_interactions | bool | True | All menu types | Exclua a mensagem imediata pela mensagem de bot e resposta do usuário quando perguntado sobre qual página eles gostariam de ir ao usar ReactionButton.Type.GO_TO_PAGE |
rows_requested | int | None | ReactionMenu.TypeEmbedDynamic | A quantidade de informações por ReactionMenu.add_row() que você gostaria de ser aplicado a cada página de incorporação |
remove_extra_emojis | bool | False | All menu types | Se True , todos os emojis (reações) adicionados à mensagem de menu que não foram originalmente adicionados ao menu serão removidos |
Dependendo do menu_type , as páginas podem ser um str , discord.Embed ou uma combinação de content e files (exemplo abaixo)
menu_type for ReactionMenu.TypeEmbed , use incorporaçõesmenu_type for ReactionMenu.TypeText (apenas menu de texto) ou ReactionMenu.TypeEmbedDynamic (menu apenas incorporado), use strings.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!' ) Um menu TypeText é um menu de paginação baseado em texto. Nenhuma incorporação está envolvida no processo de paginação, apenas o texto simples é usado.
Com v3.1.0+ , você pode paginar com mais do que apenas uma incorporação ou texto. Você pode combinar texto, incorporação e arquivos. Mas, dependendo do menu_type a combinação pode ser restrita. Aqui está um exemplo de um menu com um menu_type de TypeEmbed que é empilhado.
# 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 () Como o menu_type é TypeEmbed , sempre deve haver uma incorporação em cada página. Se o menu_type foi TypeText , as incorporações não serão permitidas e você será restrito a usar apenas o parâmetro files .
Um menu dinâmico é usado quando você não sabe quanta informação será aplicada ao menu. Por exemplo, se você solicitar informações de um banco de dados, essas informações sempre podem alterar. Você consulta algo e poderá obter 1.500 resultados de volta, e o próximo talvez apenas 800. Um menu dinâmico peças de todas essas informações juntas para você e a adiciona a uma página de incorporação por linhas de dados. ReactionMenu.add_row() é melhor usado em algum tipo de Iterable onde tudo pode ser loop, mas apenas adicione a quantidade de dados que você deseja à página de menu.
Nota: Em um menu dinâmico, todos os dados adicionados são colocados na seção Descrição de um incorporação. Se você optar por usar um
custom_embed, todo o texto na descrição será substituído pelos dados que você adicionar
ReactionMenu.add_row(data: str)ReactionMenu.clear_all_row_data()ReactionMenu.set_main_pages(*embeds: Embed)ReactionMenu.set_last_pages(*embeds: Embed)rows_requested - A quantidade de linhas que você gostaria em cada página de incorporação antes de fazer uma nova páginaReactionMenu(..., rows_requested=5)custom_embed - Uma incorporação que você criou para usar como páginas incorporadas. Usado para o seu menu estéticoReactionMenu(..., custom_embed=red_embed)wrap_in_codeblock - O identificador de idioma ao envolver seus dados em um Discord CodeBlock.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 ) Você pode remover todos os dados que você adicionou a um menu usando menu.clear_all_row_data()
Ao usar um menu dinâmico, as únicas páginas de incorporação que você vê são dos dados que você adicionou. Mas se você deseja mostrar mais páginas que não sejam apenas os dados, pode usar os métodos ReactionMenu.set_main_pages() e ReactionMenu.set_last_pages() . Definindo a (s) página (s) principal (s), as incorporações que você definir serão as primeiras incorporação que são mostradas quando o menu iniciar. Configurando as últimas páginas são as últimas incorporações mostradas
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 orderOs tipos de botões/botões são usados quando você deseja adicionar uma reação ao menu que faça uma determinada função. Botões e tipos de botões funcionam juntos para alcançar a ação desejada.
class reactionmenu.ReactionButton(*, emoji: str, linked_to: ButtonType, **kwargs)
emoji ( str ) o emoji que você gostaria de usar como a reaçãolinked_to ( ReactionButton.Type ) Quando a reação é pressionada, é isso que determina o que fará| Nome | Tipo | Valor padrão | Usado para |
|---|---|---|---|
embed | discord.Embed | None | Quando a reação for pressionada, vá para a incorporação especificada |
name | str | None | O nome do botão |
details | informações abaixo | None | Atribui a função e seus argumentos chamam quando uma ReactionButton , mas com ReactionButton.Type.CALLER é pressionada |
event | ReactionButton.Event | None | Determine quando um botão deve ser removido dependendo de quantas vezes ele foi pressionado |
skip | ReactionButton.Skip | None | Defina a ação e a quantidade de páginas para pular ao usar um linked_to de ReactionButton.Type.SKIP . Por exemplo, usando esse tipo de botão, definindo a ação como "+" e a quantidade 3. Se você estiver na "página 1/20", pressionar esse botão o levará à "página 4/20" |
| Propriedade | Tipo de retorno | Informações |
|---|---|---|
clicked_by | Set[discord.Member] | Os membros que clicaram no botão |
total_clicks | int | Quantidade de cliques do botão |
last_clicked | Optional[datetime.datetime] | O tempo no UTC para quando o botão foi clicado pela última vez |
menu | Optional[ReactionMenu] | O menu em que o botão está anexado a |
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 | Informações |
|---|---|
ReactionButton.Type.NEXT_PAGE | Vá para a próxima página na sessão de menu |
ReactionButton.Type.PREVIOUS_PAGE | Vá para a página anterior na sessão de menu |
ReactionButton.Type.GO_TO_FIRST_PAGE | Vá para a primeira página na sessão de menu |
ReactionButton.Type.GO_TO_LAST_PAGE | Vá para a última página na sessão de menu |
ReactionButton.Type.GO_TO_PAGE | Solicita que você digite a página que gostaria de ir |
ReactionButton.Type.END_SESSION | Interrompe a sessão e exclui a mensagem do menu |
ReactionButton.Type.CUSTOM_EMBED | Usado separadamente dos botões de navegação. Uma vez pressionado, vá para a incorporação especificada |
ReactionButton.Type.CALLER | Usado ao especificar a função para chamar e seus argumentos quando o botão é pressionado |
ReactionButton.Type.SKIP | Usado para paginar através de várias páginas em um único botão, pressione |
Você pode adicionar botões (reações) ao menu usando um ReactionButton . Abaixo estão exemplos de como usar cada ButtonType .
Nota: reação, mas com
ReactionButton.Type.CALLERsão um pouco diferentes, então há uma seção dedicada explicando como eles funcionam e como implementá -los mais abaixo
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 )
... Remova todos os botões com menu.remove_all_buttons() . Você também pode remover um botão individual usando o nome, se você o tiver definido, ou o próprio objeto de botão com menu.remove_button()
Os botões ReactionButton.Type.CALLER são usados para implementar sua própria funcionalidade no menu. Talvez você queira adicionar um botão que crie um canal de texto, envie uma mensagem ou adicionar algo a um banco de dados, seja qual for. Para trabalhar com ReactionButton.Type.CALLER , use o método de classe abaixo.
ReactionButton.set_caller_details(func: Callable[..., None], *args, **kwargs) Esse método de classe é usado para configurar uma função e seus argumentos que mais tarde são chamados quando o botão é pressionado. O construtor ReactionButton possui os details do KWARG, e é isso que você usará com .set_caller_details() para atribuir os valores necessários. Alguns exemplos estão abaixo de como implementar corretamente 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: A função que você passa não deve retornar nada. Chamando funções com
ReactionButton.Type.CALLERnão armazena ou lida com nada devolvido por essa função
A classe ReactionButton vem com um conjunto de métodos de fábrica (métodos de classe) que retorna um ReactionButton com parâmetros definidos de acordo com o 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 na seguinte ordem.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>)Se desejar, você pode limitar a quantidade de menus de reação que podem ser ativos ao mesmo tempo por "guilda", "membro" ou "canal"
ReactionMenu.set_sessions_limit(limit: int, per='guild', message='Too many active menus. Wait for other menus to be finished.')ReactionMenu.remove_limit()Exemplo:
@ bot . command ()
async def limit ( ctx ):
ReactionMenu . set_sessions_limit ( 3 , per = 'member' , message = 'Sessions are limited to 3 per member' )Com o exemplo acima, apenas três menus podem estar ativos de uma só vez para cada membro e, se tentarem criar mais antes que seus outros menus sejam concluídos, eles receberão uma mensagem de erro dizendo "as sessões são limitadas a 3 por membro".
Você pode definir um ReactionButton a ser removido quando for pressionado uma certa quantidade de vezes
class ReactionButton.Event(event_type: str, value: int)
event_type ( str ) a ação a ser tomada. A única opção disponível é "Remover"value ( int ) o valor definido para o evento especificado. Deve ser> = 1. Se o valor for <= 0, é implicitamente definido como 1Exemplo:
menu = ReactionMenu ( ctx , ...)
# remove a button after 10 clicks
button = ReactionButton (..., event = ReactionButton . Event ( 'remove' , 10 ))
menu . add_button ( button )Nota: Não é ideal para botões com um
linked_todeReactionButton.Type.END_SESSION
Os relés de menu são funções chamadas sempre que um botão que é separado de um menu é pressionado. É considerado uma extensão de um ReactionButton com um linked_to de ReactionButton.Type.CALLER . Ao contrário dos botões de chamadas que não fornecem detalhes sobre as interações no menu, os relés.
ReactionMenu.set_relay(func: Callable[[NamedTuple], None], *, only: Optional[List[ReactionButton]]=None)ReactionMenu.remove_relay() Ao criar uma função para o seu relé, essa função deve conter um único argumento posicional. Quando um botão é pressionado, um objeto RelayPayload (uma tupla nomeado) é transmitido para essa função. Os atributos do RelayPayload são:
member ( discord.Member ) a pessoa que pressionou o botãobutton ( ReactionButton ) o botão que foi pressionadoExemplo:
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 ) O método set_relay vem com o only parâmetro. Se esse parâmetro None , todos os botões pressionados serão transmitidos. Você pode fornecer uma list de botões para esse parâmetro, para que apenas o botão pressione desses botões especificados será retransmitido.
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) Ao iniciar o menu, você tem a opção de enviar o menu para um determinado canal. Parâmetro send_to é o canal para o qual você deseja enviar o menu. Você pode definir send_to como o nome do canal ( str ), ID do canal ( int ) ou objeto de canal ( discord.TextChannel / discord.Thread ). Exemplo:
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_tonão é válido se um menu foi iniciado no DM's
Aqui está uma implementação básica do ReactionMenu que você pode copiar e colar para uma demonstração 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)
Um ViewMenu é um menu que usa o recurso de botões Discords. Com os botões, você pode habilitá -los e desativá -los, definir uma certa cor para eles com emojis, ter botões que enviam mensagens ocultas e adicione hiperlinks. Esta biblioteca oferece uma gama mais ampla de funcionalidades como quem pressionou o botão, quantas vezes foi pressionado e muito mais. Ele usa visualizações ( discord.ui.View ) para implementar a funcionalidade dos botões, mas usa alguns de seus próprios métodos para simplificar um menu de paginação por botão.
from reactionmenu import ViewMenu , ViewButtonmethod ( Union[discord.ext.commands.Context, discord.Interaction] ) Um contexto ou objeto de interaçãomenu_type ( MenuType ) A configuração do menuViewMenu.TypeEmbed , um menu de paginação de incorporação normalViewMenu.TypeEmbedDynamic , um menu de paginação incorporado com dados dinâmicosViewMenu.TypeText , um menu de paginação apenas de texto| Nome | Tipo | Valor padrão | Usado para | Informações |
|---|---|---|---|---|
wrap_in_codeblock | str | None | ViewMenu.TypeEmbedDynamic | O Identificador de Linguagem do Discord CodeBlock para envolver seus dados. Exemplo: ViewMenu(ctx, ..., wrap_in_codeblock='py') |
custom_embed | discord.Embed | None | ViewMenu.TypeEmbedDynamic | Objeto incorporado a ser usado ao adicionar dados com ViewMenu.add_row() . Usado para fins de estilo |
delete_on_timeout | bool | False | All menu types | Exclua o menu quando estiver |
disable_items_on_timeout | bool | True | All menu types | Desative os itens no menu quando o menu chegar |
remove_items_on_timeout | bool | False | All menu types | Remova os itens no menu quando o menu estiver |
only_roles | List[discord.Role] | None | All menu types | Se definido, apenas os membros com qualquer uma das funções fornecidas podem controlar o menu. O proprietário do menu sempre pode controlar o menu |
timeout | Union[int, float, None] | 60.0 | All menu types | O temporizador para quando o menu estiver fora. Pode ser None sem tempo limite |
show_page_director | bool | True | All menu types | Mostrado na parte inferior de cada página de incorporação. "Página 1/20" |
name | str | None | All menu types | Um nome que você pode definir para o menu |
style | str | "Page $/&" | All menu types | Um estilo de diretor de página personalizado que você pode selecionar. "$" representa a página atual "e" representa a quantidade total de páginas. Exemplo: ViewMenu(ctx, ..., style='On $ out of &') |
all_can_click | bool | False | All menu types | Conjuntos se todos tiverem permissão para controlar quando as páginas são 'giradas' quando os botões são clicados |
delete_interactions | bool | True | All menu types | Exclua a mensagem imediata pelo bot e mensagem de resposta do usuário quando perguntado em que página eles gostariam de ir ao usar ViewButton.ID_GO_TO_PAGE |
rows_requested | int | None | ViewMenu.TypeEmbedDynamic | A quantidade de informações por ViewMenu.add_row() que você gostaria de ser aplicado a cada página de incorporação |
Dependendo do menu_type , as páginas podem ser um str , discord.Embed ou uma combinação de content ou files (exemplo abaixo)
menu_type for ViewMenu.TypeEmbed , use incorporaçõesmenu_type for ViewMenu.TypeText (menu somente texto) ou ViewMenu.TypeEmbedDynamic (menu apenas incorporado), use strings.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!' ) Um menu TypeText é um menu de paginação baseado em texto. Nenhuma incorporação está envolvida no processo de paginação, apenas o texto simples é usado.
Com v3.1.0+ , você pode paginar com mais do que apenas uma incorporação ou texto. Você pode combinar texto, incorporação e arquivos. Mas, dependendo do menu_type a combinação pode ser restrita. Aqui está um exemplo de um menu com um menu_type de TypeEmbed que é empilhado.
# 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 () Como o menu_type é TypeEmbed , sempre deve haver uma incorporação em cada página. Se o menu_type foi TypeText , as incorporações não serão permitidas e você será restrito a usar apenas o parâmetro files .
Um menu dinâmico é usado quando você não sabe quanta informação será aplicada ao menu. Por exemplo, se você solicitar informações de um banco de dados, essas informações sempre podem alterar. Você consulta algo e poderá obter 1.500 resultados de volta, e o próximo talvez apenas 800. Um menu dinâmico peças de todas essas informações juntas para você e a adiciona a uma página de incorporação por linhas de dados. ViewMenu.add_row() é melhor usado em algum tipo de Iterable onde tudo pode ser loop, mas adicionar apenas a quantidade de dados que você deseja à página de menu.
Nota: Em um menu dinâmico, todos os dados adicionados são colocados na seção Descrição de um incorporação. Se você optar por usar um
custom_embed, todo o texto na descrição será substituído pelos dados que você adicionar
ViewMenu.add_row(data: str)ViewMenu.clear_all_row_data()ViewMenu.set_main_pages(*embeds: Embed)ViewMenu.set_last_pages(*embeds: Embed)rows_requested - A quantidade de linhas que você gostaria em cada página de incorporação antes de fazer uma nova páginaViewMenu(..., rows_requested=5)custom_embed - Uma incorporação que você criou para usar como páginas incorporadas. Usado para o seu menu estéticoViewMenu(..., custom_embed=red_embed)wrap_in_codeblock - O identificador de idioma ao envolver seus dados em um Discord CodeBlock.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 ) Você pode remover todos os dados que você adicionou a um menu usando menu.clear_all_row_data()
Ao usar um menu dinâmico, as únicas páginas de incorporação que você vê são dos dados que você adicionou. Mas se você deseja mostrar mais páginas que não sejam apenas os dados, pode usar os métodos ViewMenu.set_main_pages() e ViewMenu.set_last_pages() . Definindo a (s) página (s) principal (s), as incorporações que você definir serão as primeiras incorporação que são mostradas quando o menu iniciar. Configurando as últimas páginas são as últimas incorporações mostradas
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 orderOs botões são o que você usa para interagir com o menu. Ao contrário das reações, eles parecem mais limpos, fornecem menos problemas de limite de taxa e oferecem mais em termos de interações. Habilite e desative os botões, use hiperlinks de Markdown em suas mensagens e até envie mensagens ocultas.
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)
Um ViewButton é uma classe que representa o botão Discord. É uma subclasse de discord.ui.Button .
A seguir, são apresentadas as regras estabelecidas pela discórdia para os botões:
custom_id e não podem ter um urlurl e não podem ter um custom_idstyle ( discord.ButtonStyle ) o estilo de botãolabel ( str ) o texto no botãocustom_id ( str ) Um ID para determinar qual ação esse botão deve tomar. IDs disponíveis: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 usado para o botãoViewButton(..., emoji='?')ViewButton(..., emoji='<:miscTwitter:705423192818450453>')ViewButton(..., emoji='U000027a1')ViewButton(..., emoji='N{winking face}')url ( str ) URL para um botão com estilo discord.ButtonStyle.linkdisabled ( bool ) se o botão deve ser desativadofollowup ( ViewButton.Followup ) A mensagem enviada após o botão ser pressionado. Disponível apenas para botões que possuem um custom_id de ViewButton.ID_CALLER ou ViewButton.ID_SEND_MESSAGE . ViewButton.Followup é uma classe que possui parâmetros semelhantes a discord.abc.Messageable.send() e é usado para controlar se uma mensagem for efêmera, contém um arquivo, incorporação, TTS, etc ...event ( ViewButton.Event ) Defina um botão para ser desativado ou removido quando for pressionado uma certa quantidade de vezes | Nome | Tipo | Valor padrão | Usado para |
|---|---|---|---|
name | str | None | O nome do botão |
skip | ViewButton.Skip | None | Defina a ação e a quantidade de páginas para pular ao usar um custom_id de ViewButton.ID_SKIP . Por exemplo, definindo a ação como "+" e a quantidade 3. Se você estiver na "página 1/20", pressionar esse botão o levará à "página 4/20" |
persist | bool | False | Impede que os botões do link sejam desativados/removidos quando o menu tocar ou for interrompido para que eles possam permanecer clicáveis |
| Propriedade | Tipo de retorno | Informações |
|---|---|---|
clicked_by | Set[discord.Member] | Os membros que clicaram no botão |
total_clicks | int | Quantidade de cliques do botão |
last_clicked | Optional[datetime.datetime] | O tempo no UTC para quando o botão foi clicado pela última vez |
menu | Optional[ViewMenu] | O menu em que o botão está anexado a |
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: Quando se trata de botões com um
custom_iddeViewButton.ID_CALLER,ViewButton.ID_SEND_MESSAGE,ViewButton.ID_CUSTOM_EMBEDou link Buttons, você pode adicionar quantos desejarem no total são 25 botões ou menos. Para todos os outros IDs do botão, cada menu pode ter apenas um.
As seleções são usadas quando você deseja categorizar as informações em seu menu. As seleções só podem ser usadas quando o menu menu_type for TypeEmbed . Você deve ter em mente que discorda as limitações de quantos itens da interface do menu (linhas) podem ser aplicados a cada mensagem.
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])Exemplo:
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 ()Você pode usar esse tipo de seleção quando deseja usar a interface do usuário para selecionar uma 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() O parâmetro page_numbers para ViewSelect.GoTo pode ser usado com 3 tipos diferentes
List[int] Se definido como uma lista de números inteiros, esses valores especificados são as únicas opções disponíveis quando a seleção é clicadapage_numbers=[1, 5, 10]Dict[int, Union[str, discord.Emoji, discord.PartialEmoji]] Você pode usar esse tipo se quiser utilizar emojis em sua seleçãopage_numbers={1 : "?️", 2 : ""}ellipsis Você pode definir uma elipse literal para que a biblioteca atribua automaticamente todos os números de página à quantidade de páginas que você adicionou ao menu. Isso pode ser útil se você tiver 25 páginas ou menospage_numbers=...NOTA : Definir o parâmetro
page_numberscomo uma elipse (...) só funciona como pretendido se você adicionar a seleção para selecionar depois de adicionar páginas ao menu
@ 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]) Quando o menu estiver em execução, você pode atualizar as páginas ou botões no menu. Usando ViewMenu.update() , você pode substituir as páginas e botões. Usando ViewMenu.refresh_menu_items() Atualiza os botões que você alterou.
@ 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 () Se os botões não forem atualizados com ViewMenu.refresh_menu_items() , o menu não será atualizado ao alterar um botão.
Método ViewMenu.update(...) é usado quando você deseja substituir todos ou alguns dos botões no menu.
menu = ViewMenu (...)
# in a different .command()
await menu . update ( new_pages = [ hello_embed , goodbye_embed ], new_buttons = [ link_button , next_button ])Nota : Ao usar
ViewMenu.update(...), não há necessidade de usarViewMenu.refresh_menu_items()porque eles são atualizados durante a chamada de atualização.
A classe ViewButton vem com um conjunto de métodos de fábrica (métodos de classe) que retorna um ViewButton com parâmetros definidos de acordo com seus custom_id (excluindo botões de link).
ViewButton.link(label: str, url: str)style : discord.ButtonStyle.linklabel : <label>url : <url>ViewButton.back()style : discord.ButtonStyle.graylabel : "Back"custom_id : ViewButton.ID_PREVIOUS_PAGEViewButton.next()style : discord.ButtonStyle.graylabel : "Próximo"custom_id : ViewButton.ID_NEXT_PAGEViewButton.go_to_first_page()style : discord.ButtonStyle.graylabel : "Primeira 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 : "Seleção de página"custom_id : ViewButton.ID_GO_TO_PAGEViewButton.end_session()discord.ButtonStyle.grayViewButton.ID_END_SESSIONViewButton.all()list do ViewButton na seguinte ordem.go_to_first_page() .back() .next() .go_to_last_page() .go_to_page() .end_session()ViewButton.all_with_emojis()list do ViewButton com seus parâmetros emoji já definidos na seguinte ordem.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 () Você pode definir um ViewButton para ser desativado ou removido quando for pressionado uma certa quantidade de vezes
class ViewButton.Event(event_type: str, value: int)
event_type ( str ) a ação a ser tomada. Pode ser "desativar" ou "remover"value ( int ) o valor definido para o evento especificado. Deve ser> = 1. Se o valor for <= 0, é implicitamente definido como 1Exemplo:
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: Não é válido para botões de link. Também não é ideal para botões com um
custom_iddeViewButton.ID_END_SESSION
Os relés de menu são funções chamadas sempre que um botão que é separado de um menu é pressionado. É considerado uma extensão de um ViewButton com um ID do ViewButton.ID_CALLER . Ao contrário dos botões de chamadas que não fornecem detalhes sobre as interações no menu, os relés.
ViewMenu.set_relay(func: Callable[[NamedTuple], None], *, only: Optional[List[ViewButton]]=None)ViewMenu.remove_relay() Ao criar uma função para o seu relé, essa função deve conter um único argumento posicional. Quando um botão é pressionado, um objeto RelayPayload (uma tupla nomeado) é transmitido para essa função. Os atributos do RelayPayload são:
member ( discord.Member ) a pessoa que pressionou o botãobutton ( ViewButton ) o botão que foi pressionadoExemplo:
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 ) O método set_relay vem com o only parâmetro. Se esse parâmetro None , todos os botões pressionados serão transmitidos (exceto os botões de link porque eles não enviam eventos de interação). Você pode fornecer uma list de botões para esse parâmetro, para que apenas o botão pressione desses botões especificados será retransmitido.
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) Ao iniciar o menu, você tem a opção de enviar o menu para um determinado canal. Parâmetro send_to é o canal para o qual você deseja enviar o menu. Você pode definir send_to como o nome do canal ( str ), ID do canal ( int ) ou objeto de canal ( discord.TextChannel / discord.Thread ). Exemplo:
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_tonão é válido se um menu foi iniciado no DM's
Apenas uma opção está disponível ao interromper o menu. Se você tiver vários parâmetros como True , apenas um será executado
delete_menu_message > disable_buttonsdisable_buttons > remove_buttons Aqui está uma implementação básica do ViewMenu que você pode copiar e colar para uma demonstração 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 ())