【问题标题】:disable a button after being used使用后禁用按钮
【发布时间】:2022-09-25 17:43:29
【问题描述】:

最近我决定重写我的不和谐机器人并添加按钮。 到目前为止我遇到的主要问题是,我不能禁用按钮刚被按下人们告诉button.disabled=True,实际上,它会禁用按钮,但它只是发送它被禁用,所以它永远不能被按下。我想要的是能够点击它并做它的事情然后禁用它。

作为参考,我会放一些代码

我使用 disnake,一个 discord.py 分支,它的语法与 spy 相同,但我们有按钮和斜线命令、下拉菜单等

class BlurpleButton(Button):
    def __init__(self, label, emoji=None):
        super().__init__(label=label, style=discord.ButtonStyle.blurple, emoji=emoji)

这是为了更容易使用按钮,我创建了一个模板,我可以在任何命令上使用它

class CustomView(View):
    def __init__(self, member: disnake.Member):
        self.member = member
        super().__init__(timeout=180)

    async def interaction_check(self, inter: disnake.MessageInteraction) -> bool:
        if inter.author != self.member:
            await inter.response.send_message(content=\"You don\'t have permission to press this button.\", ephemeral=True)
            return False
        return True

这是因为按钮只能由提到的成员按下,例如,如果我这样做/test @member(由于不和谐的新特权意图,我迁移到斜线命令)只有该成员能够按下它而没有其他人。

到目前为止一切正常,现在我们在命令中“组装”

@commands.slash_command(description=\'test\')
    async def test(self, inter):

         (do stuff in there)
         . . .
        button1 = BlurpleButton(\"Button name\")
        view=CustomView(member)
        view.add_item(button1)

        async def button_callback(inter):
            await inter.send(embed=embedname2)

        button1.callback = button_callback
        await inter.send(embed=embed1, view=view)

现在再一次,这段代码正在做它打算做的事情,发送一个嵌入(让我们只是说我把......很少嵌入)并附加到我们有@的那个嵌入987654326@ 当它被点击时它发送embedname2 并且有些地方不再工作了,我在发送embedname2 它之后继续尝试任何方式,通过点击一个按钮来禁用自身如果我在回调中添加button1.disabled=True,则该按钮将被禁用,而不会被单击。我将回调放在命令中的主要原因是能够在按钮触发时使用嵌入,如果我把它放在子类按钮或视图中,我就不能再这样做了。

所以这是我的全部问题,如果你知道一个更好的解决方法,包括使用嵌入并且只有成员可以按下按钮,请告诉我,我有一个多星期的时间试图解决这个问题,但我无法正确解决

  • 我正是这样做的,但使用了一个名为discord-ui 的不同组件模块。逻辑应该非常相似,它的流程应该是这样的:发送嵌入,单击按钮,然后编辑消息以具有相同的嵌入和按钮,但是现在按钮设置为禁用,发送 embed2
  • 更具体地说,一旦按下按钮,它应该将自身设置为禁用,然后编辑消息以发送完全相同的组件。因为您发送的是相同的组件并且按钮属性已更新,所以按钮应发送为禁用状态。如果您遇到问题,请确保为已编辑的消息传递正确的组件,因为很容易犯错误,即发送原始按钮的副本而不是更新的按钮。
  • 如果要测试/练习的更简单的版本是在单击按钮后编辑消息,则根本没有按钮。所以它最终会成为原始嵌入。祝你好运!
  • 如果我尝试编辑它,我会得到This interaction has already been responded to before
  • 嗯,这很奇怪。同样,我不知道disnake 是如何工作的,但可能有一个简单的解决方法。您不必对交互进行两次响应。是否可以编辑消息并在同一响应中发送另一个嵌入?如果不是,则可以至少做其中一件事情,然后在交互之外再做另一件事情。但是,交互之外的那个必须放在一个条件中。

标签: python python-3.x disnake


【解决方案1】:

解释

您可以通过在按钮的回调中将button.disabled 设置为True 来完成此操作。然后,您还需要编辑原始消息以反映此更改。

代码

    @commands.slash_command(description='test')
    async def test(self, slash_inter: disnake.ApplicationCommandInteraction, member: disnake.Member):

        view = CustomView(member)
        button1 = BlurpleButton("TEST")
        view.add_item(button1)

        async def button_callback(button_inter: disnake.MessageInteraction):
            button1.disabled = True
            await button_inter.send(embed=embedname2)
            await slash_inter.edit_original_message(view=view)

        button1.callback = button_callback

        await slash_inter.send(embed=embed1, view=view)

注意:要使 /test @member 起作用,您需要在斜杠命令中添加 disnake.Member 参数。

参考

disnake.MessageInteraction

disnake.ui.Button.callback

disnake slash commands

【讨论】:

  • 最后,一个很好的答案,有这个机会你帮助我看到了我的代码中的主要问题 inter 在回调和斜杠命令 arg 中都使用了,所以它们可能被覆盖并且它不起作用,谢谢
【解决方案2】:

我使用 Pycord,而不是 Disnake,但这应该可以。您可能必须在此处或按钮回调中更改确切的方法调用。

async def interaction_check(self, inter: disnake.MessageInteraction) -> bool:
    if inter.author != self.member:
        await inter.response.send_message(content="You don't have permission to press this button.", ephemeral=True)
        return False

    # The interaction is allowed, so let's disable the button.
    # Interactions have a data field that stores the custom ID of the
    # component sent the interaction. We will use this to find our button
    # in the view.

    button_id = iter.data["custom_id"]
    [child for child in self.children if child.custom_id == button_id][0].disabled = True
    await inter.edit_original_message(view=self)

    # From this point on, you will be dealing with inter.followup, since
    # an interaction can only be responded to once.
    
    return True

【讨论】:

  • 我尝试了您的版本并遇到了多个错误,例如Unresolved reference 'child'Cannot find reference 'data' in 'function | function | function'Expected type 'collections.Iterable', got 'bool' instead'in' expected(对于循环错误)相反,我试图重新排列它pastebin.com/wuRSYFvd,但后来我得到了This interaction has already been responded to before,我不知道不明白为什么
  • @Ares 我的代码中有错字,抱歉。应该是[child for child in self.children if child.custom_id == button_id]
  • 至于之前回复的交互,需要使用interaction.followup.send()
  • 呃,现在有button_id = iter.data["b1"] AttributeError: 'builtin_function_or_method' object has no attribute 'data' 我试图解决一个问题,另一个出现了,还有Unresolved attribute reference 'disabled' for class 'Item'
  • 看起来,尽管它们都是 discord.py 的分支,但 Disnake 和 Pycord 在交互上的差异足以导致不兼容。对不起!
【解决方案3】:

我倾向于并建议为每个视图回调创建新类。通过这种方式,我可以更轻松地处理多个按钮,并且更易于阅读。随意编辑我的代码,我将把 cmets 作为方向

首先,给你的 BlurpleButton 一个自定义 ID,或者让用户在类中定义一个

(label=label, style=discord.ButtonStyle.blurple, emoji=emoji, custom_id="bttn1") # bttn1 is your custom ID, you'll use it to select this button from the view when disabling it or modifying its contents

在你的回调中,试试这个代码:

b = [x for x in self.children if x.custom_id == "bttn1"][0] # Selects the blurpleButton from the view's buttons based on the custom_id
b.disabled = True # Disable

然后通过使用这个新视图编辑您的消息来完成它

await inter.response.edit_message(view=self) # Edit that the buttons are attached to, but replacing the view with the new one containing our edits (disabling the button)

【讨论】:

  • “无法分配给列表理解”我不太理解 for 循环,如果您能在我上面的代码中显示一个示例或应该如何应用它,我将不胜感激,谢谢
  • 代码有错别字,应该是x.custom_id == "bttn1"。那么,这应该是正确的答案。
  • @Ares你应该再试一次。上面的代码对我有用。
  • @TheFungusAmongUs Unresolved reference children 这就是为什么我要求一个明确的例子适用于我上面提供的内容,因为对我来说这没有意义
猜你喜欢
  • 1970-01-01
  • 2012-11-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 2011-01-20
  • 1970-01-01
相关资源
最近更新 更多