I tried to create a simple but functioning example with your specifications as i understood them. There are a bunch of comments, but let me know if something is still not clear.
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import CallbackContext, CommandHandler, CallbackQueryHandler, Updater
from telegram.error import BadRequest
REMOVE_BUTTONS_COUNT = 5
PAGES_COUNT = 10
def get_text_and_keyboard(page: int, removed_buttons: list):
"""Generates both the text and the inline keyboard to show to the user,
based on the current page and on the buttons that have been removed
"""
# Makes sure removed_buttons is a list
text = f"You are on page {page + 1}" if page is not None else "You are on page 1"
keyboard = InlineKeyboardMarkup(
[
[InlineKeyboardButton(text=f"RESET", callback_data="reset")],
*[ # Each element generated is a row, notice the * before the [
# and the [] wrapping the InlineKeyboardButton
[InlineKeyboardButton(text=f"🗑 button {i}", callback_data=f"rm_{i}")]
for i in range(REMOVE_BUTTONS_COUNT)
if i not in removed_buttons
],
[ # All the pages are on the same row
InlineKeyboardButton(text=f"{i + 1}", callback_data=f"go_{i}")
for i in range(PAGES_COUNT)
if i != page
],
]
)
return text, keyboard
def remove_query(update: Update, context: CallbackContext):
"""Removes a button"""
# The data is in the form "rm_<number>"
button_idx = int(update.callback_query.data.replace("rm_", ""))
rm_buttons = context.user_data.get("removed_buttons", [])
rm_buttons.append(button_idx)
context.user_data["removed_buttons"] = rm_buttons
# I'm only interested in the keyboard, for the text message doesn't change
_, keyboard = get_text_and_keyboard(None, rm_buttons)
context.bot.edit_message_reply_markup(
chat_id=update.callback_query.message.chat_id,
message_id=update.callback_query.message.message_id,
reply_markup=keyboard,
)
def reset_query(update: Update, context: CallbackContext):
"""Resets both buttons and pages"""
context.user_data["removed_buttons"] = []
context.user_data["page"] = 0
text, keyboard = get_text_and_keyboard(None, [])
try:
context.bot.edit_message_text(
chat_id=update.callback_query.message.chat_id,
message_id=update.callback_query.message.message_id,
text=text,
reply_markup=keyboard,
)
except BadRequest: # The message was already in the default state
pass
def go_to_page_query(update: Update, context: CallbackContext):
"""Goes to the provided page"""
# The data is in the form "go_<number>"
new_page = int(update.callback_query.data.replace("go_", ""))
context.user_data["page"] = new_page
removed_buttons = context.user_data.get("removed_buttons", [])
text, keyboard = get_text_and_keyboard(new_page, removed_buttons)
context.bot.edit_message_text(
chat_id=update.callback_query.message.chat_id,
message_id=update.callback_query.message.message_id,
text=text,
reply_markup=keyboard,
)
def menu_cmd(update: Update, context: CallbackContext):
"""Handles the /menu command.
Shows the inline keyboard
Args:
update: update event
context: context passed by the handler
"""
# Both could be put on context.bot_data, context.chat_data, in a file or a database
# depending on your requirements.
# You may also want to reset them here
page = context.user_data.get("page", 0)
removed_buttons = context.user_data.get("removed_buttons", [])
text, keyboard = get_text_and_keyboard(page, removed_buttons)
context.bot.send_message(
chat_id=update.message.chat_id,
text=text,
reply_markup=keyboard,
)
def main():
"""Main function"""
updater = Updater("TOKEN")
updater.dispatcher.add_handler(CommandHandler("start", menu_cmd))
# Regex is used in the pattern to match the callback_data coming from the buttons
updater.dispatcher.add_handler(CallbackQueryHandler(remove_query, pattern=r"^rm_*"))
updater.dispatcher.add_handler(CallbackQueryHandler(reset_query, pattern=r"^reset$"))
updater.dispatcher.add_handler(CallbackQueryHandler(go_to_page_query, pattern=r"^go_*"))
updater.start_polling()
updater.idle()
if __name__ == "__main__":
main()