python - 如何在 python 中使 Telegram bot 动态键盘按钮在一行中的每个按钮

标签 python

我想制作一个键盘按钮(replykeyboardmarkup),它从数据库中读取数据,并显示键盘每一行上的每个按钮。

我想在电报机器人中创建自定义键盘。例如:我们有一个从数据库中获取的字符串数组。我们如何将数据从数组推送到 InlineKeyboardMarkup?动态响应按钮。

我能做什么?

最佳答案

Telegram Bot API他们没有提到如何处理动态 InlineKeyboardButton .但是有一种方法可以使用 CallbackQuery 来做这种事情。 .在下面的示例中,假设 stringList 变量将保存数据库查询结果,为此我使用 stringList 作为 Pyton DictionaryPython 3.7pyTelegramBotAPI这是 Telegram Bot API 的工具.

stringList = {"Name": "John", "Language": "Python", "API": "pyTelegramBotAPI"}

让我们通过从 telebot 导入类型来根据 stringList 创建按钮。在这里,callback_data 用一个 List 实现,它帮助我们将数据从按钮传递到查询处理程序。如果您的callback_data 超过 64 字节,则有一个限制 Telegram Bot API将生成 BUTTON_DATA_INVALID 响应。更多信息请引用 Markup Errors以避免此类异常。

markup = types.InlineKeyboardMarkup()

for key, value in stringList.items():
    markup.add(types.InlineKeyboardButton(text=value,
                                          callback_data="['value', '" + value + "', '" + key + "']"),
               types.InlineKeyboardButton(text=crossIcon,
                                          callback_data="['key', '" + key + "']"))

下图是上面代码的结果。

Result of the InlineKeyboardButton

我正在使用这个十字图标向您展示如何删除动态按钮以及如何编辑 InlineKeyboardButton删除那个动态按钮。正如你所看到的(上面的代码)有两个 CallbackQuery它处理第一个按钮和十字按钮。

您可以在以下代码行中捕获第一个按钮的callback_data

if (call.data.startswith("['value'")):
    print(f"call.data : {call.data} , type : {type(call.data)}")
    print(f"ast.literal_eval(call.data) : {ast.literal_eval(call.data)} , type : {type(ast.literal_eval(call.data))}")
    valueFromCallBack = ast.literal_eval(call.data)[1]
    keyFromCallBack = ast.literal_eval(call.data)[2]
    bot.answer_callback_query(callback_query_id=call.id, show_alert=True,
                              text="You Clicked " + valueFromCallBack + " and key is " + keyFromCallBack)

有两个打印语句可以准确地查看我们要处理的数据类型。当我们单击 John 的第一个按钮时,第一个打印语句向我们显示字符串类型列表。

call.data : ['value', 'John', 'Name'] , type : <class 'str'>

我们几乎接近解决方案,但是使用字符串类型 List。我通过引用这个 question 的答案找到了将字符串类型 List 转换为普通 List 的解决方案。 . python ast抽象语法树(Abstract Syntax Trees)是表示源代码抽象句法结构的模块。使用ast.literal_eval()我们可以从第二个打印语句中得到以下输出。

ast.literal_eval(call.data) : ['value', 'John', 'Name'] , type : <class 'list'>

由于 answerCallbackQuery 同时显示此警报我们在上面的代码中使用了它。

Result of the answerCallbackQuery

我们可以得到这样的输出,因为我们用值列表填充了按钮。同样,您可以在 callback_data 中传递列表并在 callback_query_handler 中处理该列表。让我们看一下单击十字图标时会发生什么。

if (call.data.startswith("['key'")):
    keyFromCallBack = ast.literal_eval(call.data)[1]
    del stringList[keyFromCallBack]
    bot.edit_message_text(chat_id=call.message.chat.id,
                          text="Here are the values of stringList", message_id=call.message.message_id,
                          reply_markup=makeKeyboard(), parse_mode='HTML')

它将转到 answerCallbackQuery以“'[key'”开头并删除Pyton Dictionary通过使用给定的键 (del stringList[keyFromCallBack])。让我们点击第一个十字图标,看看会发生什么。

Regenerate dynamic buttons according to the List

第一个按钮将消失,因为editMessageText使用可用的词典详细信息重新生成。而不是删除 Pyton Dictionary你可以调用一些数据库查询。

这里是上面例子的完整代码。

import telebot
import ast
import time
from telebot import types

bot = telebot.TeleBot("YOUR_BOT_API_KEY_HERE")

stringList = {"Name": "John", "Language": "Python", "API": "pyTelegramBotAPI"}
crossIcon = u"\u274C"

def makeKeyboard():
    markup = types.InlineKeyboardMarkup()

    for key, value in stringList.items():
        markup.add(types.InlineKeyboardButton(text=value,
                                              callback_data="['value', '" + value + "', '" + key + "']"),
        types.InlineKeyboardButton(text=crossIcon,
                                   callback_data="['key', '" + key + "']"))

    return markup

@bot.message_handler(commands=['test'])
def handle_command_adminwindow(message):
    bot.send_message(chat_id=message.chat.id,
                     text="Here are the values of stringList",
                     reply_markup=makeKeyboard(),
                     parse_mode='HTML')

@bot.callback_query_handler(func=lambda call: True)
def handle_query(call):

    if (call.data.startswith("['value'")):
        print(f"call.data : {call.data} , type : {type(call.data)}")
        print(f"ast.literal_eval(call.data) : {ast.literal_eval(call.data)} , type : {type(ast.literal_eval(call.data))}")
        valueFromCallBack = ast.literal_eval(call.data)[1]
        keyFromCallBack = ast.literal_eval(call.data)[2]
        bot.answer_callback_query(callback_query_id=call.id,
                              show_alert=True,
                              text="You Clicked " + valueFromCallBack + " and key is " + keyFromCallBack)

    if (call.data.startswith("['key'")):
        keyFromCallBack = ast.literal_eval(call.data)[1]
        del stringList[keyFromCallBack]
        bot.edit_message_text(chat_id=call.message.chat.id,
                              text="Here are the values of stringList",
                              message_id=call.message.message_id,
                              reply_markup=makeKeyboard(),
                              parse_mode='HTML')
while True:
    try:
        bot.polling(none_stop=True, interval=0, timeout=0)
    except:
        time.sleep(10)

要测试此代码,请在您的机器人窗口中输入/test 命令。

关于python - 如何在 python 中使 Telegram bot 动态键盘按钮在一行中的每个按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45558984/

相关文章:

python - 为什么python openCV不按我期望的方式更改背景颜色?

php - 将值从 python 传递到 php

python - 当列表超出 Python 范围时返回特定值

python - Python 2.6 的 Str.format() 给出错误,而 2.7 没有

python - 在线性回归中使用 PCA

Python不连接字符串和unicode来链接

python - 在 Matplotlib 中删除楔形极坐标图周围的空间

python - 迭代卡住集与集合的内存差异

python - 具有至少 1 个唯一列值的随机 DataFrame 样本

Python socketserver - 与 threading.Lock() 交互?