Найти в Дзене
Записки сисадмина

Python. Telegram bot. Кнопки и клавиатуры в сообщениях. Часть 1

Оглавление

Как же хочется иногда навести суеты. А еще хочется навести красоты. Красоты для пользователей своих проектов. Чтобы им было удобно и приятно пользоваться плодами нашего умственного труда.

А что сейчас считается модным? Конечно же - минимум механических действий с получением максимального результата.

Иначе говоря, я не хочу печатать какую-то команду боту, я хочу просто нажимать на кнопочки и получать то, что мне нужно.

Итак, существует всего два типа людей... Ой, существует всего два типа клавиатур у телеграм ботов: те, что заменяют обычную клавиатуру и те, что прикрепляются к сообщениям.

Но обо всем по порядку.

Reply Keyboard

Технически - самая простая клавиатура. При активации, перекрывает обычную клавиатуру с буквами. Используется для пошагового взаимодействия с пользователем.

Если объяснять очень грубо - внутри каждой кнопки находится текст. Нажатие на эту кнопку отправляет сообщение с текстом внутри нее. Но давайте от теории к практике:

  • Импортируем необходимые модули для нашей клавиатуры:
from telebot.types import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove
  • Создадим нашу клавиатуру
kb = ReplyKeyboardMarkup()
  • Добавим в нее кнопки "да" и "нет"

Можно так:

-2

Можно так:

-3

А можно вообще так:

-4

Все три записи абсолютно идентичны.

А для чего мы вообще создавали эту клавиатуру? Как ее вывести пользователю?

Любая клавиатура прикрепляется к сообщению бота в параметре reply_markup.

  • Создадим обработчик команды /start и к сообщению бота прикрепим нашу клавиатуру:
-5

@bot.message_handler(commands=['start'])

def start_message(message):

bot.send_message(message.chat.id, 'Начнем диалог?', reply_markup=kb)

-6

Какие большие и некрасивые кнопки у нас получились.

  • Используем параметр resize_keyboard при создании клавиатуры:
-7
kb = ReplyKeyboardMarkup(resize_keyboard=True)
kb.add('Да', 'Нет')
-8

Все здорово и красиво, но при нажатии на кнопки ничего не происходит. Вы просто отправляете сообщения в чат. Технически, да, при нажатии на KeyboardButton, автоматически формируется и отправляется текстовое сообщение.

Возникает вопрос: как правильно нам его обработать?

В теории, мы можем написать два обработчика текстовых сообщений, по типу:

@bot.message_handler(func=lambda message: message.text == 'Да')
@bot.message_handler(func=lambda message: message.text == 'Нет')

Но нужно помнить то, что эти обработчики будут перехватывать все сообщения с текстом "Да" и "Нет", что нас абсолютно не устраивает. Так мы плавно подходим к последовательности сообщений, к методу register_next_step_handler.

bot.register_next_step_handler()

Метод помогает строить многоуровневое меню, либо вести диалог с пользователем.

Как это работает:

При вызове метода мы должны передать минимум 2 аргумента: переменную, которую мы передаем дальше, и в какую функцию мы передаем.

  • Давайте напишем нашу новую функцию:
-9

Заметьте, у функции нет никакого декоратора, она будет отрабатывать только тогда, когда ее вызовут.

  • Дописываем нашу изначальную функцию:
-10
  • Проверяем, как это работает:
-11

Заметим: наша клавиатура никуда не исчезла, но новые нажатия на нее не дают никакого результата.

  • Прописываем автоматическое закрытие клавиатуры:
-12

Можно написать так, однако, я советую выносить функцию закрытия в отдельную переменную:

-13
@bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, 'Начнем диалог?', reply_markup=kb)
bot.register_next_step_handler(message, second_message)
def second_message(old_message):
bot.send_message(old_message.chat.id, f'Твой выбор был {old_message.text}', reply_markup=kb_remove)
-14

Убирать клавиатуру полностью нужно только тогда, когда ваш прогнозируемый диалог подошел к концу.

А можно ли передать в функцию больше одной переменной?

Конечно, да! Пробуем:

-15
def second_message(message):
first_text = message.text
second_msg = bot.send_message(message.chat.id, f'Сделай второй выбор', reply_markup=kb)
additional_param = 'Текстовая переменная'
bot.register_next_step_handler(second_msg, third_message, first_text, additional_param)

Здесь мы создали переменную "additional_param", в которую мы поместили простой текст.

  • В методе register_next_step_handler мы передаем по очереди:
  1. Новое сообщение
  2. Вызываемую функцию
  3. Любое количество дополнительных переменных (функция должна будет принять их все)

def third_message(second_mess, start_text, new_param):
bot.send_message(second_mess.chat.id, f'''Текст твоих сообщений:
Первое: {start_text}
Второе: {second_mess.text}
Дополнительная переменная из второй функции: {new_param}
''', reply_markup=kb_remove)

При попадании в функцию third_message():

  1. переменная second_msg стала second_mess
  2. first_text стала start_text
  3. additional_param стала new_param.

Смотрим, как это отрабатывает:

-16

Такую последовательность сообщений можно вести бесконечно, но лучше не увлекаться и делать меню в 2-3 уровня.

В следующей статье поговорим о кнопках, прикрепляемых к сообщениям.

Код из этой статьи выложил здесь