Proper way to build menus with python-telegram-bot

前端 未结 2 1856
忘掉有多难
忘掉有多难 2020-12-13 11:06

I work with python-telegram-bot and try to build a system of nested menus as BotFather bot does. For instance, you have a general bot menu

相关标签:
2条回答
  • 2020-12-13 11:29

    You should use an argument pattern in CallbackQueryHandler. Also is a good thing use a classes or functions for keyboards and messages.
    To return to main menu add return button to submenu with specific callback pattern.

    Please note: you use edit_message_text in menu. It's mean nothing will happen if you will call start function with reply_text method from any menu.

    Full working example with functions:

    #!/usr/bin/env python3.8
    from telegram.ext import Updater
    from telegram.ext import CommandHandler, CallbackQueryHandler
    from telegram import InlineKeyboardButton, InlineKeyboardMarkup
    ############################### Bot ############################################
    def start(bot, update):
      bot.message.reply_text(main_menu_message(),
                             reply_markup=main_menu_keyboard())
    
    def main_menu(bot, update):
      bot.callback_query.message.edit_text(main_menu_message(),
                              reply_markup=main_menu_keyboard())
    
    def first_menu(bot, update):
      bot.callback_query.message.edit_text(first_menu_message(),
                              reply_markup=first_menu_keyboard())
    
    def second_menu(bot, update):
      bot.callback_query.message.edit_text(second_menu_message(),
                              reply_markup=second_menu_keyboard())
    
    def first_submenu(bot, update):
      pass
    
    def second_submenu(bot, update):
      pass
    
    def error(update, context):
        print(f'Update {update} caused error {context.error}')
    
    ############################ Keyboards #########################################
    def main_menu_keyboard():
      keyboard = [[InlineKeyboardButton('Menu 1', callback_data='m1')],
                  [InlineKeyboardButton('Menu 2', callback_data='m2')],
                  [InlineKeyboardButton('Menu 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('XXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 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.dispatcher.add_error_handler(error)
    
    updater.start_polling()
    ################################################################################
    

    Sorry, i have two spaces in tab. :)

    UPD: Fix submenu object.

    0 讨论(0)
  • 2020-12-13 11:36

    great answer by @dzNET. But it won't work in V12 so I changed a little bit

    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()
    

    Again thanks to @dzNET

    0 讨论(0)
提交回复
热议问题