فصل ۱۰: کار با دکمههای Inline و Callback Query در ربات تلگرام

مقدمه فصل
وقتی شما یک ربات تلگرام میسازید، راههای زیادی برای تعامل با کاربر دارید. یکی از جذابترین روشها، استفاده از دکمههایی است که زیر پیام ظاهر میشوند و کاربر با یک کلیک، درخواست یا فرمان خاصی به ربات میدهد. به این نوع دکمهها دکمههای Inline گفته میشود.
در این فصل، ما:
- دکمههای Inline رو تعریف میکنیم.
- با مفهوم Callback Query آشنا میشویم.
- روش ساخت یک منوی ساده با دکمه Inline را یاد میگیریم.
- مثال پیشرفته منوی چندمرحلهای را پیادهسازی میکنیم.
- اشتباهات رایج و نکات حرفهای را بررسی میکنیم.
بخش ۱: دکمههای Inline چیست؟
دکمههای Inline (In-message Buttons) دکمههایی هستند که درون یک پیام تلگرام تعبیه میشوند و دقیقا زیر همان پیام نمایش داده میشوند.
مثال کاربرد آنها:
- ارسال لینکهای وبسایت بدون وارد کردن متن در چت
(مثلاً دکمه “مشاهده محصول” که کاربر را به سایت فروش هدایت میکند) - منوهای چند مرحلهای در ربات بدون شلوغ شدن چت
(مثلاً منو انتخاب دسته آموزش → انتخاب زبان برنامهنویسی → نمایش محتوا) - گرفتن نظر یا پاسخ سریع از کاربر
(مثلاً نظرسنجی با دکمه «بله» و «خیر»)
ویژگی دکمههای Inline:
| ویژگی | توضیح |
|---|---|
| ظاهر شکیل | دکمه درون پیام است و چت کاربر را شلوغ نمیکند. |
| تعامل مستقیم | با استفاده از Callback Query، کلیک کاربر بلافاصله به ربات اعلام میشود. |
| پشتیبانی از لینک | میتوان به جای ارسال فرمان، لینک یک سایت را قرار داد. |
بخش ۲: Callback Query چیست؟
وقتی کاربر روی یک دکمه Inline کلیک میکند، تلگرام به جای اینکه یک پیام جدید به ربات بفرستد، یک شیء (Object) به نام Callback Query ارسال میکند.
این شیء شامل اطلاعاتی مثل:
- callback_query_id → شناسهای برای پاسخ دادن به آن
- from → اطلاعات کاربری که کلیک کرده
- data → همان دادهای که شما موقع ساخت دکمه در
callback_dataگذاشتهاید
به زبان ساده:
Callback Query مثل پیام مخفیای است که تلگرام به ربات شما میفرستد و میگوید کاربر فلان دکمه را فشار داده است.
بخش ۳: نصب کتابخانه python-telegram-bot
برای کار با تلگرام در پایتون، کتابخانهی معروف و قابل اعتماد python-telegram-bot را استفاده میکنیم.
برای نصب:
pip install python-telegram-bot==20.3
نکته: نسخه ۲۰۳ به بعد این کتابخانه، از ساختار Async (غیرهمزمان) استفاده میکند، یعنی توابع ربات باید با
asyncتعریف شوند و برای صدا زدن تابعها ازawaitاستفاده میکنیم.
بخش ۴: ساخت یک ربات با یک دکمه Inline ساده
بیایید یک مثال ساده بزنیم: منویی که از کاربر میخواهد زبان خود را انتخاب کند.
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import ApplicationBuilder, CommandHandler, CallbackQueryHandler, ContextTypes
TOKEN = "توکن_ربات_اینجا"
# تابع /start
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
keyboard = [
[InlineKeyboardButton("🇮🇷 فارسی", callback_data="lang_fa")],
[InlineKeyboardButton("🇬🇧 English", callback_data="lang_en")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("زبان خود را انتخاب کنید:", reply_markup=reply_markup)
# تابعی که کلیک روی دکمه را مدیریت میکند
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer() # توقف لودینگ تلگرام
if query.data == "lang_fa":
await query.edit_message_text(text="زبان فارسی انتخاب شد ✅")
elif query.data == "lang_en":
await query.edit_message_text(text="English language selected ✅")
# ساخت اپلیکیشن
app = ApplicationBuilder().token(TOKEN).build()
# اضافه کردن هندلرها
app.add_handler(CommandHandler("start", start))
app.add_handler(CallbackQueryHandler(button_handler))
print("ربات فعال شد...")
app.run_polling()
بخش ۵: توضیح خطبهخط کد بالا
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
این خط، کلاسهای لازم برای ساخت دکمه و کیبورد Inline را ایمپورت میکند:
- InlineKeyboardButton → برای ساخت یک دکمه
- InlineKeyboardMarkup → برای گروهبندی دکمهها در قالب کیبورد
- Update → شیئی که داده آپدیت را از تلگرام دریافت میکند
from telegram.ext import ApplicationBuilder, CommandHandler, CallbackQueryHandler, ContextTypes
اینجا ابزارهای مورد نیاز برای راهاندازی ربات را وارد میکنیم:
- ApplicationBuilder → ساخت اسکلت اصلی ربات
- CommandHandler → مدیریت دستورات مثل
/start - CallbackQueryHandler → مدیریت کلیک روی دکمهها
- ContextTypes → مدیریت اطلاعات جانبی در طول اجرا
TOKEN = "توکن_ربات_اینجا"
اینجا باید توکن رباتی که از BotFather گرفتهاید را وارد کنید.
- تابع start:
keyboard = [
[InlineKeyboardButton("🇮🇷 فارسی", callback_data="lang_fa")],
[InlineKeyboardButton("🇬🇧 English", callback_data="lang_en")],
]
ما یک لیست دوبعدی ساختیم:
- هر لیست داخلی یک ردیف کیبورد را تشکیل میدهد.
- هر دکمه با عنوان و
callback_data(داده برگشتی) ساخته میشود.
reply_markup = InlineKeyboardMarkup(keyboard)
لیست دکمهها را به یک شیء کیبورد تبدیل میکند.
await update.message.reply_text("زبان خود را انتخاب کنید:", reply_markup=reply_markup)
پیامی به کاربر ارسال میکند و کیبورد را زیر آن پیام نمایش میدهد.
- تابع button_handler:
query = update.callback_query
await query.answer()
update.callback_queryاطلاعات کلیک را میدهد.query.answer()لودینگ تلگرام را متوقف میکند (اجباری است).
if query.data == "lang_fa":
await query.edit_message_text(text="زبان فارسی انتخاب شد ✅")
query.dataهمانcallback_dataاست که در دکمه تعریف کردهایم.- بهجای ارسال پیام جدید، پیام قبلی را ویرایش میکنیم تا چت شلوغ نشود.
- ساخت اپلیکیشن و اضافه کردن هندلرها:
app = ApplicationBuilder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(CallbackQueryHandler(button_handler))
app.run_polling()
run_polling()یعنی ربات منتظر بماند و هر آپدیت جدید تلگرام را بررسی کند.
بخش ۶: ساخت منوی چندمرحلهای با دکمههای Inline
فرض کنید میخواهیم یک منوی چندمرحلهای بسازیم که کاربر اول دستهبندی انتخاب کند، بعد زیرمنو را ببیند.
کد:
async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
keyboard = [
[InlineKeyboardButton("📚 آموزش", callback_data="cat_tutorial")],
[InlineKeyboardButton("📰 اخبار", callback_data="cat_news")],
]
await update.message.reply_text(
"یک دستهبندی را انتخاب کنید:",
reply_markup=InlineKeyboardMarkup(keyboard)
)
async def menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
if query.data == "cat_tutorial":
keyboard = [
[InlineKeyboardButton("Python", callback_data="tutorial_py")],
[InlineKeyboardButton("Django", callback_data="tutorial_dj")],
]
await query.edit_message_text(
"موضوع آموزش:",
reply_markup=InlineKeyboardMarkup(keyboard)
)
elif query.data == "cat_news":
keyboard = [
[InlineKeyboardButton("Technology", callback_data="news_tech")],
[InlineKeyboardButton("Sports", callback_data="news_sport")],
]
await query.edit_message_text(
"موضوع اخبار:",
reply_markup=InlineKeyboardMarkup(keyboard)
)
توضیح کد:
- در
menuمنوی اصلی ساخته میشود. - در
menu_callbackبسته به انتخاب کاربر، منوی جدید ساخته و جایگزین پیام قبلی میشود. - با این روش، فقط یک پیام برای کل منو استفاده میشود.
بخش ۷: سوالات متداول (FAQ)
سوال: آیا میتوان روی دکمه Inline لینک گذاشت؟
پاسخ: بله، در سازنده دکمه به جای callback_data از url='https://example.com' استفاده کنید.
سوال: محدودیت طول callback_data چیست؟
حداکثر ۶۴ بایت.
سوال: آیا میشود بهصورت همزمان متن پیام را تغییر نداد ولی عملیات انجام داد؟
بله، کافیست از query.answer(text="پیام کوتاه") استفاده کنید تا نوتیفیکیشن کوتاهی روی صفحه کاربر بیاید.
بخش ۸: اشتباهات رایج
| اشتباه | توضیح |
|---|---|
ننوشتن query.answer() | باعث میشود لودینگ تلگرام تمام نشود. |
طولانی کردن callback_data | به خاطر محدودیت ۶۴ بایت ارور خواهد داد. |
ارسال پیام جدید بهجای edit_message_text | باعث شلوغ شدن گفتوگو میشود. |
بخش ۹: نکات تکمیلی و حرفهای
- میتوانید
callback_dataرا به شکل JSON کوچک شده ارسال کنید و در سمت ربات باjson.loadsبخوانید. - از سیستم State برای مدیریت منوهای پیچیده استفاده کنید.
- دادههای انتخاب شده کاربر را در دیتابیس ذخیره کنید تا بعداً بتوانید تجربه شخصیسازیشده بدهید.
- برای ظاهر بهتر، از ایموجی در نام دکمهها استفاده کنید.