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

discord.py按钮触发选择菜单及CSV操作功能实现求助

问题分析与修复方案

你的代码存在几个关键问题导致功能无法实现:

  • ItemSelectMenu的options是类属性,会在程序启动时就初始化,无法获取点击按钮后才读取的可用物品列表
  • 发送选择菜单时错误使用了channel.send,没有通过交互响应发送临时消息
  • 缺少用户选择后将用户名写入CSV的逻辑
  • 没有将读取到的可用物品列表传递给选择菜单实例

以下是修复后的完整代码:

import discord
from discord import ui
from discord.ext import commands
import os
import csv
from dotenv import load_dotenv
load_dotenv('config.env')

client = commands.Bot(command_prefix='!', intents=discord.Intents.all())

@client.command()
async def item(ctx):
    view = ItemButtonMenu()
    await ctx.send("Choose an item:", view=view)

class ItemButtonMenu(ui.View):
    def __init__ (self, *, timeout=None):
        super().__init__(timeout=timeout)
    
    @ui.button(label='Take item', custom_id='take_item', style=discord.ButtonStyle.green)
    async def take_item(self, interaction: discord.Interaction, button: ui.Button):
        # 读取CSV中的可用物品
        available_items = []
        with open('items.csv', 'r', newline='') as csvfile:
            csvreader = csv.reader(csvfile)
            next(csvreader)  # 跳过表头
            available_items = [row[0] for row in csvreader if row[1].strip() == '']
        
        if not available_items:
            await interaction.response.send_message("目前没有可用物品!", ephemeral=True)
            return
        
        # 创建选择菜单并传入可用物品
        view = ItemSelectMenu(available_items=available_items)
        # 通过交互响应发送临时选择菜单
        await interaction.response.send_message("选择你要领取的物品:", view=view, ephemeral=True)

class ItemSelectMenu(ui.View):
    def __init__(self, available_items: list, *, timeout=None):
        super().__init__(timeout=timeout)
        # 动态生成选择选项
        options = [discord.SelectOption(label=item) for item in available_items]
        # 将选择组件添加到视图
        self.add_item(ui.Select(
            placeholder='Choose an item',
            options=options,
            custom_id='item_select'
        ))
    
    @ui.select(custom_id='item_select')
    async def item_select(self, select: ui.Select, interaction: discord.Interaction):
        selected_item = select.values[0]
        username = interaction.user.name
        
        # 将用户名写入CSV对应的物品行
        rows = []
        updated = False
        with open('items.csv', 'r', newline='') as csvfile:
            csvreader = csv.reader(csvfile)
            rows = list(csvreader)
            # 遍历行,找到对应物品并更新
            for idx, row in enumerate(rows):
                if idx == 0:  # 跳过表头
                    continue
                if row[0] == selected_item and row[1].strip() == '':
                    rows[idx][1] = username
                    updated = True
                    break
        
        if updated:
            with open('items.csv', 'w', newline='') as csvfile:
                csvwriter = csv.writer(csvfile)
                csvwriter.writerows(rows)
            await interaction.response.send_message(f"你已成功领取物品:{selected_item}", ephemeral=True)
        else:
            await interaction.response.send_message("该物品已被他人领取,请刷新后重试!", ephemeral=True)

token: str = os.getenv('TOKEN')
client.run(token)

关键修改说明

  1. 动态传递可用物品:将available_items作为参数传入ItemSelectMenu的构造函数,避免依赖类属性导致的初始化时机问题
  2. 正确使用交互响应:用interaction.response.send_message替代channel.send,确保临时消息发送给触发按钮的用户
  3. 添加CSV写入逻辑:用户选择物品后,读取整个CSV文件,找到对应物品的行并更新用户名,再写回文件
  4. 增加异常情况处理:判断是否有可用物品,以及物品是否在选择过程中被他人领取,给出相应提示
  5. 优化CSV读写:使用newline=''避免写入时出现空行,用strip()处理空字符串的空格问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:48:11