0

0

如何在 discord.py 中动态创建模块化选择菜单

心靈之曲

心靈之曲

发布时间:2026-01-05 14:54:09

|

281人浏览过

|

来源于php中文网

原创

如何在 discord.py 中动态创建模块化选择菜单

本文介绍如何基于字典数据动态生成 discord 选择菜单(select menu),实现无需为每个问题重复定义 view 类的模块化设计,支持随机抽题、自动绑定选项与回调逻辑,并可链式推进多轮问答。

在使用 discord.py 构建交互式问答系统(如分院帽式性格测试)时,若将题目与选项硬编码进多个 View 类中,会导致代码冗余、难以维护。理想方案是:仅用一个可复用的 View 类,通过传入不同题目字典动态渲染菜单。以下是经过验证的专业级实现方式。

✅ 正确做法:运行时构建 View 类 + 装饰器绑定回调

核心思路是——在函数作用域内动态定义 View 子类,并用 @discord.ui.select 装饰其方法。这样每次调用都能生成一个携带当前题目上下文的新 View 实例,避免闭包陷阱和异步回调绑定错误。

Animate AI
Animate AI

Animate AI是个一站式AI动画故事视频生成工具

下载
import random
import discord
from discord import ui, Interaction

# 示例题库(可扩展为 Q1, Q2, ..., Q8)
Q1 = {
    "Aube ou crépuscule": {
        "Aube": {"gry": 73, "serd": 73, "pouf": 30, "serp": 26},
        "Crépuscule": {"gry": 27, "serd": 27, "pouf": 70, "serp": 74}
    },
    "Forêt ou rivière": {
        "Forêt": {"gry": 74, "serd": 73, "pouf": 26, "serp": 28},
        "Rivière": {"gry": 26, "serd": 27, "pouf": 74, "serp": 72}
    }
}

# 主要问答函数(支持递归/链式调用)
async def questionnaire_choixpeau(
    interaction: Interaction, 
    question_dict: dict, 
    user_id: int,
    is_first: bool = True
):
    # 1️⃣ 随机抽取一道题
    question = random.choice(list(question_dict.keys()))

    # 2️⃣ 动态构建 SelectOption 列表
    options = [
        discord.SelectOption(label=label) 
        for label in question_dict[question].keys()
    ]

    # 3️⃣ 在函数内定义 View 类(关键!确保每次调用都新建类,避免状态污染)
    class QuestionView(ui.View):
        def __init__(self):
            super().__init__(timeout=300)  # 5分钟超时

        @ui.select(
            placeholder=question,
            min_values=1,
            max_values=1,
            options=options
        )
        async def select_callback(self, ctx: Interaction, select: ui.Select):
            # 解析用户选择并更新数据库(示例)
            selected_label = select.values[0]
            scores = question_dict[question][selected_label]

            # ⚠️ 注意:此处需替换为你的真实数据库操作
            # cursor.execute("UPDATE ...", (*scores.values(), user_id))

            # 4️⃣ 链式调用下一道题(示例逻辑)
            next_dict = get_next_question_dict(question_dict)  # 请自行实现映射逻辑
            if next_dict:
                await ctx.response.defer()  # 防止响应超时
                await questionnaire_choixpeau(ctx, next_dict, user_id, is_first=False)
            else:
                await ctx.response.edit_message(
                    content="✅ 问卷已完成!正在计算分院结果...",
                    embed=None,
                    view=None
                )
                # await attribution_maison(ctx, user_id)

    # 5️⃣ 发送消息(首次用 send_message,后续用 edit_message)
    embed = discord.Embed(title="? 请选择一个答案", description=f"**{question}**")
    for opt in options:
        embed.add_field(name="", value=f"• {opt.label}", inline=False)

    if is_first:
        await interaction.response.send_message(
            embed=embed, 
            view=QuestionView(), 
            ephemeral=True
        )
    else:
        await interaction.response.edit_message(embed=embed, view=QuestionView())

# 辅助函数:返回下一题字典(可根据实际需求改为列表索引或字典映射)
def get_next_question_dict(current: dict) -> dict | None:
    # 示例:按 Q1→Q2→...→Q8 顺序推进
    mapping = {Q1: Q2, Q2: Q3, Q3: Q4, Q4: Q5, Q5: Q6, Q6: Q7, Q7: Q8}
    return mapping.get(current)

⚠️ 关键注意事项

  • 不要在 __init__ 中手动赋值 callback:select.callback = ... 会传入协程对象而非可调用函数,引发 TypeError: 'coroutine' object is not callable。
  • 禁止在类外定义 @ui.select 方法:装饰器必须作用于 View 子类内部方法,否则无法注册事件处理器
  • 动态 View 类必须每次新建:若复用同一类,@ui.select 的 placeholder 和 options 将被缓存为首次调用值,导致后续题目显示错误。
  • 响应方式要区分首次与后续:首次用 interaction.response.send_message();后续必须用 interaction.response.edit_message()(因原消息已存在)。
  • 务必设置 timeout 并处理超时:长时间未响应的 View 应自动禁用,避免用户误点旧菜单。

✅ 总结

该方案实现了真正意义上的模块化、可复用、上下文感知的选择菜单系统
? 题目数据与 UI 逻辑完全解耦;
? 支持任意层级的链式问答流程;
? 无硬编码 View 类,降低维护成本;
? 兼容 ephemeral 模式,保障用户隐私。

只需将你的题库组织为嵌套字典,并实现 get_next_question_dict() 映射逻辑,即可快速部署完整分院测试系统。

相关专题

更多
go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

133

2025.07.29

漫蛙2入口地址合集
漫蛙2入口地址合集

本专题整合了漫蛙2入口汇总,阅读专题下面的文章了解更多详细内容。

162

2026.01.06

AO3中文版地址汇总
AO3中文版地址汇总

本专题整合了AO3中文版地址合集,阅读专题下面的文章了解更多详细内容。

86

2026.01.06

python cv2模块教程大全
python cv2模块教程大全

本专题整合了python cv2模块相关教程,阅读专题下面的文章了解更多详细教程。

41

2026.01.06

python创建txt文件教程大全
python创建txt文件教程大全

本专题整合了python创建txt文件相关教程,阅读专题下面的文章了解更多详细内容。

21

2026.01.06

python去掉字符串空格教程大全
python去掉字符串空格教程大全

本专题整合了python去掉字符串空格教程大全,阅读专题下面的文章了解更多详细内容。

2

2026.01.06

Python /与// 教程大全
Python /与// 教程大全

本专题整合了python的/和//的相关内容大全,阅读下面的文章了解更多详细内容。

23

2026.01.06

Python /与// 教程大全
Python /与// 教程大全

本专题整合了python的/和//的相关内容大全,阅读下面的文章了解更多详细内容。

0

2026.01.06

Python /与// 教程大全
Python /与// 教程大全

本专题整合了python的/和//的相关内容大全,阅读下面的文章了解更多详细内容。

0

2026.01.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 2.8万人学习

SciPy 教程
SciPy 教程

共10课时 | 1万人学习

Sass 教程
Sass 教程

共14课时 | 0.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号