Видели когда-нибудь рекламные посты в каналах с прикрепленной большой прозрачной кнопкой "перейти", или "подписаться"? А видели многоуровневые меню с такими же кнопками?
В этой статье мы уже разобрались с клавиатурами, которые перекрывают стандартные буквенные клавиатуры у пользователя. А как же нам прикрепить кнопки к сообщениям? Добро пожаловать в мир Inline клавиатур.
В отличии от KeyboardButton, в InlineKeyboardButton внутри зашит не только текст, но и дополнительные данные, например URL, или callback. Давайте разбираться.
URL в кнопке
- Импортируем необходимые модули:
from telebot.types import InlineKeyboardButton, InlineKeyboardMarkup
- Создадим нашу клавиатуру с единственной кнопкой "подписаться":
inline_kb = InlineKeyboardMarkup()
button = InlineKeyboardButton(text='Подписаться на канал', url='https://dzen.ru/sys_notes')
inline_kb.add(button)
- И создадим функцию, которая будет отправлять сообщение с прикрепленной кнопкой:
@bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, 'Подпишись на канал, здесь много всего интересного', reply_markup=inline_kb)
При нажатии на кнопку, телеграм предложит перейти по тому URL, который был указан внутри.
В отличии от ReplyKeyboard, которая перекрывает клавиатуру, InlineKeyboard прикрепляется к сообщению, и ее можно убрать только отредактировав это самое сообщение с помощью bot.edit_message().
Callback'и, и с чем их едят
Callback — это функция, которая передается в качестве аргумента другой функции и вызывается после завершения некоторого действия. Используется для обработки событий и позволяет писать более гибкий и расширяемый код.
Давайте сразу обозначим два принципа, которые нужно соблюдать всегда:
- Callback_data должна всегда обрабатываться.
- Вы всегда должны отвечать на callback пользователю.
- Давайте создадим клавиатуру для регистрации пользователя:
reg_keyboard = InlineKeyboardMarkup()
reg_keyboard.add(InlineKeyboardButton(text='Подписаться', callback_data='register_yes'),
InlineKeyboardButton(text='Отказаться', callback_data='register_no',))
- Напишем обработчик команды /reg, который будет отправлять нашу клавиатуру:
@bot.message_handler(commands=['reg'])
def reg_message(message):
bot.send_message(message.chat.id, 'Хотите подписаться?', reply_markup=reg_keyboard)
Все замечательно работает, только при нажатии на кнопки не происходит ничего.
Все правильно, нам нужно как-то обрабатывать callback'и, которые отправляют наши кнопки. В этом нам поможет декоратор callback_query_handler. Так же, как message_handler обрабатывает все сообщения, callback_query_handler обрабатывает все callback'и.
- Напишем обработчик:
Обратим внимание, что на вход мы получаем не привычный message, а call (вызов).
При выводе call мы получим json от api telegram, схожий с тем, что мы получали от сообщений. В самом конце мы увидим 'data': 'register_yes'.
Все, что мы указали в параметры кнопки callback_data, попадет в call.data.
- Начинаем обрабатывать наши callback'и.
Вроде как работает.
На самом деле, нет. Вспоминаем, что нам необходимо ответить на callback, иначе вызов не завершится и мы не сможем повторно нажать на кнопку.
- Дописываем ответы на callback:
@bot.callback_query_handler(func=lambda call: True)
def call_handler(call):
match call.data:
case 'register_yes':
bot.send_message(call.message.chat.id, 'Registered')
bot.answer_callback_query(callback_query_id=call.id, text='Successfully registered')
case 'register_no':
bot.send_message(call.message.chat.id, 'Not registered')
bot.answer_callback_query(callback_query_id=call.id, text='Not registered')
Вот теперь все точно отрабатывает как нужно. Текст, который вы укажете в answer_callback_query, будет показан пользователю при ответе на callback.
В следующей статье я покажу, как сделать Inline клавиатуры еще проще, а так же создадим наше первое многоуровневое меню.