Python-Telegram-Bot点击InlineKeyboardButton后如何等待用户输入
解决方案
问题根因
- 会话处理器(ConversationHandler)的入口配置错误,未覆盖Inline按钮触发的场景,且原有回调处理函数吞掉了
jkpMenu返回的状态值,导致状态跳转失败 jokenpo函数误用while循环,python-telegram-bot是事件驱动框架,每一次用户输入只会触发一次函数调用,死循环会导致程序直接跑完逻辑不会等待用户输入- 获取用户输入的对象错误:后续用户发送的是普通文本消息,不再是回调请求,不能从
update.callback_query拿内容 - 全局变量存储游戏数据会导致多用户使用时数据冲突,建议改用上下文存储
修正步骤
1. 修改回调处理函数,透传状态返回值
原有comQuery返回类型为None,会吞掉jkpMenu返回的状态,需要修改为返回状态值:
def comQuery(update: Update, context: CallbackContext) -> int: query = update.callback_query query.answer() if query.data == 'clog': changelog(update, context) return ConversationHandler.END # 其他非游戏功能直接结束会话 if query.data == 'info': myInfo(update, context) return ConversationHandler.END if query.data == 'jokenpo': return jkpMenu(update, context) # 透传游戏菜单返回的状态值
2. 修正jokenpo函数逻辑,适配事件驱动模式
删掉while循环,每次处理完用户输入后返回JKP状态等待下一次输入,同时调整用户输入获取方式,改用上下文存储游戏数据:
# Jokenpo 1: 问候与规则说明 def jkpMenu(update: Update, context: CallbackContext) -> int: # 初始化游戏数据存入user_data,避免多用户冲突 context.user_data['varScore'] = 0 context.user_data['varLives'] = 5 context.user_data['varTie'] = 0 update.callback_query.message.reply_text('Jokenpo mode. Please type "rock", "paper" or "scissors" to continue') return JKP # Jokenpo 2: 游戏逻辑处理 def jokenpo(update: Update, context: CallbackContext) -> int: msgUser = update.message.text.lower() # 普通消息从update.message拿内容 game_data = context.user_data computer = random.choice(("rock", "paper", "scissors")) if (msgUser== "rock" and computer == "paper") or (msgUser== "paper" and computer == "scissors") or (msgUser=="scissors" and computer == "rock"): update.message.reply_text(f"Computer chooses <i>{computer}</i>. <b>You lose!</b>", parse_mode ='HTML') game_data['varLives'] -= 1 elif (msgUser== "rock" and computer == "scissors") or (msgUser == "paper" and computer == "rock") or (msgUser == "scissors" and computer == "paper"): update.message.reply_text(f"Computer chooses <i>{computer}</i>. <b>You win!</b>", parse_mode ='HTML') game_data['varScore'] +=1 elif (msgUser== computer): update.message.reply_text(f"We both chose <i>{computer}</i>. <b>It's a tie!</b>", parse_mode ='HTML') game_data['varTie'] +=1 elif (msgUser== "status"): update.message.reply_text(f"Your current score: {game_data['varScore']} points.\nYou have {game_data['varLives']} lives left.\nWe tied {game_data['varTie']} times.") return JKP # 查询状态后继续等待用户输入 # 结束判断 if (msgUser== "sair") or (game_data['varLives'] == 0): update.message.reply_text(f"Game finished. You made <b>{game_data['varScore']}</b> points.\nWe tied {game_data['varTie']} times.\n", parse_mode ='HTML') # 清空用户数据 context.user_data.clear() return ConversationHandler.END update.message.reply_text('Please choose: paper, rock or scissors? ') return JKP # 返回状态继续等待下一次输入
3. 修正ConversationHandler配置
把入口调整为包含Inline回调触发的路径:
def main(): # 其他处理器注册... convHandler = ConversationHandler( entry_points=[ CommandHandler('jokenpo', jkpMenu), # 保留原命令触发入口 CallbackQueryHandler(comQuery) # 新增Inline按钮回调作为入口 ], fallbacks=[], states = { JKP: [MessageHandler(Filters.text & ~Filters.command, jokenpo)] # 过滤掉命令,只处理普通文本 }) dp.add_handler(convHandler) # 其他启动逻辑...
内容的提问来源于stack exchange,提问作者Rogell Paradox
相关产品推荐
相关产品推荐

