You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py语音支持机器人按钮多次触发问题求助

Fixing Multiple Trigger Issues with Discord.py Buttons

Hey there, let's tackle this button multiple-trigger problem you're facing. The core issue here is that your global on_button listener is firing multiple times when you click a single button—usually because you've got multiple embed messages with buttons using similar custom IDs, and the listener isn't isolating the specific button that was clicked or locking its state after the first interaction.

Here are a few solid solutions to fix this:

This is the most straightforward fix: disable the clicked button right away to prevent re-triggering, plus it gives users clear feedback that their action was registered. Update your on_button listener like this:

@bot.listen("on_button")
async def on_button(btn):
    # Filter for our close/abuse buttons
    custom_id = btn.component.custom_id
    if not (custom_id.startswith("close-") or custom_id.startswith("abuse-")):
        return

    # Disable the button to stop further triggers
    await btn.disable()

    # Extract the target channel ID from the custom ID
    channel_id = custom_id.split("-")[1]
    target_channel = bot.get_channel(int(channel_id))

    # Handle the button action
    if custom_id.startswith("close-"):
        if target_channel:
            await target_channel.delete()
        await btn.respond(content="Ticket closed successfully!", delete_after=2)
    elif custom_id.startswith("abuse-"):
        # Add your abuse reporting logic here (e.g., notify admins)
        admin_channel = bot.get_channel(your_admin_channel_id_here)
        await admin_channel.send(f"Abuse reported for voice channel {channel_id}!")
        await btn.respond(content="Abuse report submitted!", delete_after=2)

    print(f"Processed button: {custom_id}")

Why this works:

  • The button grays out instantly, so users won't accidentally click it again
  • Each button is only processed once, eliminating duplicate triggers

2. Track Processed Messages to Avoid Re-runs

If you need to keep buttons enabled for some reason, you can track which messages have already been acted on using a set to store processed message IDs:

# Store IDs of messages we've already handled
processed_messages = set()

@bot.listen("on_button")
async def on_button(btn):
    # Skip if this message was already processed
    if btn.message.id in processed_messages:
        return

    # Mark the message as processed
    processed_messages.add(btn.message.id)

    # Your existing button logic here
    custom_id = btn.component.custom_id
    print(f"Processed button: {custom_id}")
    # ... rest of your code

Note:

Make sure to clean up this set periodically (e.g., after the associated voice channel is deleted) to avoid memory bloat over time.

3. Use Component Callbacks (Cleaner Approach with discord_ui)

The discord_ui library lets you bind callback functions directly to buttons when you create them, instead of using a global listener. This keeps your logic tied to the specific button and avoids cross-triggering issues:

# Define callback functions for each button
async def handle_close(btn):
    channel_id = btn.component.custom_id.split("-")[1]
    target_channel = bot.get_channel(int(channel_id))
    if target_channel:
        await target_channel.delete()
    await btn.disable()
    await btn.respond(content="Ticket closed!", delete_after=2)

async def handle_abuse(btn):
    channel_id = btn.component.custom_id.split("-")[1]
    admin_channel = bot.get_channel(your_admin_channel_id_here)
    await admin_channel.send(f"Abuse reported for channel {channel_id}!")
    await btn.disable()
    await btn.respond(content="Report sent to admins!", delete_after=2)

# Send the embed with buttons bound to their callbacks
@bot.event
async def on_voice_state_update(member, before, after):
    try:
        if after.channel.id == int("944642625351327784"):
            if before.channel is None and after.channel is not None:
                notifychannel = bot.get_channel(944642626055979059)
                embed = discord.Embed(title="test")
                notifyembed = await ui.components.send(notifychannel, embed=embed, components=[
                    Button("Close", f"close-{uservoicechannel.id}", "green", emoji="✅", callback=handle_close),
                    Button("Abuse!", f"abuse-{uservoicechannel.id}", "red", emoji="️", new_line=False, callback=handle_abuse)
                ])
    except:
        pass

Why this is great:

  • Your button logic lives right where the button is created, making code easier to maintain
  • No global listener conflicts—each button's callback is independent

Quick Note on the Root Cause

The multiple triggers likely happen because your global on_button listener responds to all button clicks, not just the specific one you clicked. When you have multiple embed messages with buttons using similar custom IDs, the listener can end up processing the same action multiple times (or the listener itself might be registered multiple times if your code reloads). The fixes above all address this by isolating the specific button interaction or preventing re-runs.

内容的提问来源于stack exchange,提问作者Luca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 13:58:12