在Telegram Bot API 中,他们没有提到如何处理动态InlineKeyboardButton。但是有一种方法可以使用CallbackQuery 来做这种事情。在以下示例中,假设 stringList 变量将保存数据库查询结果,为此我使用 stringList 作为 Pyton Dictionary 与 Python 3.7 和 pyTelegramBotAPI是为Telegram Bot API 实现的。
stringList = {"Name": "John", "Language": "Python", "API": "pyTelegramBotAPI"}
让我们根据 stringList 通过从 telebot 导入类型来创建按钮。在这里 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 + "']"))
下图是上面代码的结果。
我正在使用这个十字图标向您展示如何删除动态按钮以及如何通过删除该动态按钮来编辑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 的第一个按钮时,第一个打印语句向我们显示字符串类型 List。
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。
我们可以得到这样的输出,因为我们用值列表填充按钮。同样,您可以在 callback_data 中传递 List 并在 callback_query_handler 中处理该 List。我们来看看点击十字图标会发生什么。
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')
它将转到以“'[key'”开头的answerCallbackQuery,并使用给定的密钥(del stringList[keyFromCallBack])删除Pyton Dictionary。让我们点击第一个十字图标看看会发生什么。
第一个按钮将消失,因为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 命令。