我想制作一个键盘按钮(replykeyboardmarkup
),它从数据库中读取数据,并显示键盘每一行上的每个按钮。
我想在电报机器人中创建自定义键盘。例如:我们有一个从数据库中获取的字符串数组。我们如何将数据从数组推送到 InlineKeyboardMarkup?动态响应按钮。
我能做什么?
最佳答案
在Telegram Bot API他们没有提到如何处理动态 InlineKeyboardButton .但是有一种方法可以使用 CallbackQuery 来做这种事情。 .在下面的示例中,假设 stringList 变量将保存数据库查询结果,为此我使用 stringList 作为 Pyton Dictionary与 Python 3.7和 pyTelegramBotAPI这是 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 + "']"))
下图是上面代码的结果。
我正在使用这个十字图标向您展示如何删除动态按钮以及如何编辑 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 同时显示此警报我们在上面的代码中使用了它。
我们可以得到这样的输出,因为我们用值列表填充了按钮。同样,您可以在 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]
)。让我们点击第一个十字图标,看看会发生什么。
第一个按钮将消失,因为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/