我使用python-telegram-bot
并尝试像BotFather机器人一样构建嵌套菜单系统。例如,您有一个常规的漫游器菜单
您可以在其中选择“编辑机器人”并获得相应的新菜单
具有返回上一级菜单的选项。
我尝试通过代码来实现:
# main menu
def start(bot, update):
menu_main = [[InlineKeyboardButton('Option 1', callback_data='m1')],
[InlineKeyboardButton('Option 2', callback_data='m2')],
[InlineKeyboardButton('Option 3', callback_data='m3')]]
reply_markup = InlineKeyboardMarkup(menu_main)
update.message.reply_text('Choose the option:', reply_markup=reply_markup)
# all other menus
def menu_actions(bot, update):
query = update.callback_query
if query.data == 'm1':
# first submenu
menu_1 = [[InlineKeyboardButton('Submenu 1-1', callback_data='m1_1')],
[InlineKeyboardButton('Submenu 1-2', callback_data='m1_2')]]
reply_markup = InlineKeyboardMarkup(menu_1)
bot.edit_message_text(chat_id=query.message.chat_id,
message_id=query.message.message_id,
text='Choose the option:',
reply_markup=reply_markup)
elif query.data == 'm2':
# second submenu
# first submenu
menu_2 = [[InlineKeyboardButton('Submenu 2-1', callback_data='m2_1')],
[InlineKeyboardButton('Submenu 2-2', callback_data='m2_2')]]
reply_markup = InlineKeyboardMarkup(menu_2)
bot.edit_message_text(chat_id=query.message.chat_id,
message_id=query.message.message_id,
text='Choose the option:',
reply_markup=reply_markup)
elif query.data == 'm1_1':
...
elif query.data == 'm1_2':
...
# and so on for every callback_data option
...
# handlers
dispatcher.add_handler(CommandHandler('start', start))
dispatcher.add_handler(CallbackQueryHandler(menu_actions))
此代码有效,但我感觉这是不合理的-构建一棵长elif
树。
此外,我不知道如何为用户提供从第二级菜单返回主菜单的选项(因为主菜单位于另一个处理程序中,并且我无法通过回调来捕获它)来自CallbackQueryHandler
)。
问题是-构建这种菜单系统的最佳实践是什么?
答案 0 :(得分:8)
您应该在pattern
中使用参数CallbackQueryHandler
。将类或函数用于键盘和消息也是一件好事。
要返回主菜单,请使用特定的回调模式将返回按钮添加到子菜单。
请注意:您在菜单中使用edit_message_text
。这意味着,如果您从任何菜单使用start
方法调用reply_text
函数,都不会发生任何事情。
具有功能的完整示例:
#!/usr/bin/python3
from telegram.ext import Updater
from telegram.ext import CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
############################### Bot ############################################
def start(bot, update):
update.message.reply_text(main_menu_message(),
reply_markup=main_menu_keyboard())
def main_menu(bot, update):
query = update.callback_query
bot.edit_message_text(chat_id=query.message.chat_id,
message_id=query.message.message_id,
text=main_menu_message(),
reply_markup=main_menu_keyboard())
def first_menu(bot, update):
query = update.callback_query
bot.edit_message_text(chat_id=query.message.chat_id,
message_id=query.message.message_id,
text=first_menu_message(),
reply_markup=first_menu_keyboard())
def second_menu(bot, update):
query = update.callback_query
bot.edit_message_text(chat_id=query.message.chat_id,
message_id=query.message.message_id,
text=second_menu_message(),
reply_markup=second_menu_keyboard())
# and so on for every callback_data option
def first_submenu(bot, update):
pass
def second_submenu(bot, update):
pass
############################ Keyboards #########################################
def main_menu_keyboard():
keyboard = [[InlineKeyboardButton('Option 1', callback_data='m1')],
[InlineKeyboardButton('Option 2', callback_data='m2')],
[InlineKeyboardButton('Option 3', callback_data='m3')]]
return InlineKeyboardMarkup(keyboard)
def first_menu_keyboard():
keyboard = [[InlineKeyboardButton('Submenu 1-1', callback_data='m1_1')],
[InlineKeyboardButton('Submenu 1-2', callback_data='m1_2')],
[InlineKeyboardButton('Main menu', callback_data='main')]]
return InlineKeyboardMarkup(keyboard)
def second_menu_keyboard():
keyboard = [[InlineKeyboardButton('Submenu 2-1', callback_data='m2_1')],
[InlineKeyboardButton('Submenu 2-2', callback_data='m2_2')],
[InlineKeyboardButton('Main menu', callback_data='main')]]
return InlineKeyboardMarkup(keyboard)
############################# Messages #########################################
def main_menu_message():
return 'Choose the option in main menu:'
def first_menu_message():
return 'Choose the submenu in first menu:'
def second_menu_message():
return 'Choose the submenu in second menu:'
############################# Handlers #########################################
updater = Updater('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(main_menu, pattern='main'))
updater.dispatcher.add_handler(CallbackQueryHandler(first_menu, pattern='m1'))
updater.dispatcher.add_handler(CallbackQueryHandler(second_menu, pattern='m2'))
updater.dispatcher.add_handler(CallbackQueryHandler(first_submenu,
pattern='m1_1'))
updater.dispatcher.add_handler(CallbackQueryHandler(second_submenu,
pattern='m2_1'))
updater.start_polling()
################################################################################
对不起,我在标签中有两个空格。 :)
答案 1 :(得分:4)
@dzNET的绝佳回答。但这在V12中不起作用,所以我做了一些改动
from telegram.ext import CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
############################### Bot ############################################
def start(update, context):
update.message.reply_text(main_menu_message(),
reply_markup=main_menu_keyboard())
def main_menu(update,context):
query = update.callback_query
query.answer()
query.edit_message_text(
text=main_menu_message(),
reply_markup=main_menu_keyboard())
def first_menu(update,context):
query = update.callback_query
query.answer()
query.edit_message_text(
text=first_menu_message(),
reply_markup=first_menu_keyboard())
def second_menu(update,context):
query = update.callback_query
query.answer()
query.edit_message_text(
text=second_menu_message(),
reply_markup=second_menu_keyboard())
# and so on for every callback_data option
def first_submenu(bot, update):
pass
def second_submenu(bot, update):
pass
############################ Keyboards #########################################
def main_menu_keyboard():
keyboard = [[InlineKeyboardButton('Option 1', callback_data='m1')],
[InlineKeyboardButton('Option 2', callback_data='m2')],
[InlineKeyboardButton('Option 3', callback_data='m3')]]
return InlineKeyboardMarkup(keyboard)
def first_menu_keyboard():
keyboard = [[InlineKeyboardButton('Submenu 1-1', callback_data='m1_1')],
[InlineKeyboardButton('Submenu 1-2', callback_data='m1_2')],
[InlineKeyboardButton('Main menu', callback_data='main')]]
return InlineKeyboardMarkup(keyboard)
def second_menu_keyboard():
keyboard = [[InlineKeyboardButton('Submenu 2-1', callback_data='m2_1')],
[InlineKeyboardButton('Submenu 2-2', callback_data='m2_2')],
[InlineKeyboardButton('Main menu', callback_data='main')]]
return InlineKeyboardMarkup(keyboard)
############################# Messages #########################################
def main_menu_message():
return 'Choose the option in main menu:'
def first_menu_message():
return 'Choose the submenu in first menu:'
def second_menu_message():
return 'Choose the submenu in second menu:'
############################# Handlers #########################################
updater = Updater('YOUR_TOKEN_HERE', use_context=True)
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(main_menu, pattern='main'))
updater.dispatcher.add_handler(CallbackQueryHandler(first_menu, pattern='m1'))
updater.dispatcher.add_handler(CallbackQueryHandler(second_menu, pattern='m2'))
updater.dispatcher.add_handler(CallbackQueryHandler(first_submenu,
pattern='m1_1'))
updater.dispatcher.add_handler(CallbackQueryHandler(second_submenu,
pattern='m2_1'))
updater.start_polling()
再次感谢@dzNET