Proper way to build menus with python-telegram-bot
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.8from telegram.ext import Updaterfrom telegram.ext import CommandHandler, CallbackQueryHandlerfrom 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): passdef second_submenu(bot, update): passdef 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.
great answer by @dzNET. But it won't work in V12 so I changed a little bit
from telegram.ext import CommandHandler, CallbackQueryHandlerfrom 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 optiondef first_submenu(bot, update): passdef 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