Загрузка...

Ready (crutch, but working) inline clave with pagination

Thread in Python created by killmator Jun 30, 2022. (bumped Jul 1, 2022) 3,292 views

  1. killmator
    На форуме уже несколько человек спрашивали, как сделать инлайн клаву с пагинацией, и я не исключение.
    Написал вот такую хуйню за полтора часа. Понимаю, что можно было гораздо проще сделать, но хоть что-то. Новичкам !!!как я!!! точно зайдет, по крайней мере самим думать не надо будет:pokerwhite:.
    Если что просто скрипт, добавляете его к своему проекту сами:Bratishka:

    Надеюсь я хоть чем-то помог:clown:

    ПРУФ:


    UPD: у моего варика много недочётов (global, колбеки на Далее и Назад отдельные, хотя можно было в один объединить и тп), но тут другие накидали свои варианты реализации :podumai:, так что - пользуйтесь на здоровье.

    Python
    from main import dp
    from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
    from aiogram.dispatcher import FSMContext
    from aiogram.dispatcher.filters.state import State, StatesGroup
    from aiogram import types

    res = ['1', '2', '3'] # будущие элементы вашей инлайн клавы, не надо их импортировать через global, это просто пример списка чтоб компилятор не ругался


    class Menu(StatesGroup):
    step = State()


    def get_splitted_lst(lst, n): #делим наш список на части по столько элементов, сколько вы указали
    new = []
    for i in range(0, len(lst), n):
    new.append(lst[i:i + n])
    return new


    def upgrate_keyboard(part_of_list): #создание клавы
    part = part_of_list
    size = len(part) - 1
    the_keyboard = InlineKeyboardMarkup()
    for i in range(size + 1):
    button = InlineKeyboardButton(text=str(part[i]), callback_data='the_step')
    the_keyboard.add(button)
    next_button = InlineKeyboardButton(text='Далее', callback_data='next_step')
    back_button = InlineKeyboardButton(text='Назад', callback_data='back_step')
    stop_button = InlineKeyboardButton(text='Закончить просмотр', callback_data='stop')
    the_keyboard.row(back_button, next_button).add(stop_button)
    return the_keyboard


    async def create_buttons(a, space, default): # главная функция - (список для будущей пагинации, по сколько нужно выводить под сообщением, тут просто 0)
    splitted_list = get_splitted_lst(a, space)
    universal_dict = {}
    for i in range(len(splitted_list)):
    universal_dict[i] = splitted_list[i]
    print(f'разбитый на странички массив{universal_dict}')
    your_keyboard = upgrate_keyboard(list(universal_dict.get(default))) #готовая клава с инлайн кнопками
    return your_keyboard


    @dp.message_handler(text='/test', state='*')
    async def enter_test(message: types.Message, state: FSMContext):
    global res
    await message.answer('Меню', reply_markup=await create_buttons(res, 3, 0)) # мой список, 3 - по сколько выводить в самой клаве, 0 - тут просто 0 должно быть)
    await Menu.step.set()
    async with state.proxy() as data:
    data['res'] = 0


    @dp.callback_query_handler(text='next_step', state=Menu.step)
    async def next_menu(callback: types.CallbackQuery, state: FSMContext):
    try:
    global res
    async with state.proxy() as data:
    data['res'] = data['res'] + 1
    data = await state.get_data()
    await callback.message.edit_text('Меню', reply_markup=await create_buttons(res, 3, data.get('res')))
    except TypeError:
    async with state.proxy() as data:
    data['res'] = data['res'] - 1
    await callback.message.delete()
    await callback.message.answer('Меню', reply_markup=await create_buttons(res, 3, data.get('res')))


    @dp.callback_query_handler(text='back_step', state=Menu.step)
    async def back_menu(callback: types.CallbackQuery, state: FSMContext):
    try:
    global res
    async with state.proxy() as data:
    data['res'] = data['res'] - 1
    data = await state.get_data()
    await callback.message.edit_text('Меню', reply_markup=await create_buttons(res, 3, data.get('res')))
    except TypeError:
    async with state.proxy() as data:
    data['res'] = data['res'] + 1
    await callback.message.delete()
    await callback.message.answer('Меню', reply_markup=await create_buttons(res, 3, data.get('res')))


    @dp.callback_query_handler(text='stop', state=Menu.step)
    async def newk_sui3(callback: types.CallbackQuery, state: FSMContext):
    await callback.message.delete()
    await callback.message.answer('Подбор закончен')
    await state.finish()
     
  2. urlykk
    urlykk Jun 30, 2022 288 Jun 26, 2019
    на далее и назад можно было бы возвращать на стартовую/последнюю
    + вывод страницы в кнопке бы сделать

    глобалы лучше вообще не использовать

    ну и сплитанный лист можно было бы так сделать (но читаемость хуже)
    Python
    splitted_list = [lst[i:i + n] for i in range(0, len(lst), n)]
     
    1. killmator Topic starter
      avatarurlykk, глобал только для примера вставил, написал же. А все остальное - по делу, спс
  3. cpp_inactive3442203
    cpp_inactive3442203 Jun 30, 2022 Banned 59 Jul 30, 2020
    Необоснованное использование global тоже?
    Про билдер в аиограмме не слышал?
    Переобразование существующей функции питона...
     
    1. View previous comments (2)
    2. cpp_inactive3442203
      avatarcpp_inactive3442203, from aiogram.utils.keyboard import ReplyKeyboardBuilder
      Немного про срался, для inline нет таких:/
    3. cpp_inactive3442203
      avatarurlykk, странно, я в доках искал и не нашёл, Мб ввёл "online" вместо "inline" :roflanFacepalm:
  4. vtlstolyarov
    Что же вы так любите кучу повторяющегося и лишнего кода писать?
    Python
    from main import dp
    from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
    from aiogram.dispatcher import FSMContext
    from aiogram.dispatcher.filters.state import State, StatesGroup
    from aiogram import types

    res = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] # будущие элементы вашей инлайн клавы, не надо их импортировать через global, это просто пример списка чтоб компилятор не ругался
    PAGE_SIZE = 3 # по сколько выводить в самой клаве

    class Menu(StatesGroup):
    step = State()


    async def answer_with_menu(message: types.Message, state: FSMContext, menu_page_shift: int):
    global res
    async with state.proxy() as data:
    current_page_index = data['res']
    new_page_index = current_page_index + menu_page_shift
    if (new_page_index < 0 or new_page_index > len(res)/PAGE_SIZE):
    new_page_index = current_page_index
    data['res'] = new_page_index

    the_keyboard = InlineKeyboardMarkup()
    index = new_page_index * PAGE_SIZE
    for text in res[index:index + PAGE_SIZE]:
    button = InlineKeyboardButton(text=text, callback_data='the_step')
    the_keyboard.add(button)
    next = InlineKeyboardButton(text='Назад', callback_data='back_step')
    back = InlineKeyboardButton(text='Далее', callback_data='next_step')
    stop = InlineKeyboardButton(text='Закончить просмотр', callback_data='stop')
    the_keyboard.row(next, back).add(stop)

    await message.answer('Меню', reply_markup=the_keyboard)


    @dp.message_handler(text='/test', state='*')
    async def enter_test(message: types.Message, state: FSMContext):
    await Menu.step.set()
    async with state.proxy() as data:
    data['res'] = 0
    await answer_with_menu(message, state, 0)


    @dp.callback_query_handler(text='next_step', state=Menu.step)
    async def next_menu(callback: types.CallbackQuery, state: FSMContext):
    await callback.message.delete()
    await answer_with_menu(callback.message, state, +1)


    @dp.callback_query_handler(text='back_step', state=Menu.step)
    async def back_menu(callback: types.CallbackQuery, state: FSMContext):
    await callback.message.delete()
    await answer_with_menu(callback.message, state, -1)


    @dp.callback_query_handler(text='stop', state=Menu.step)
    async def newk_sui3(callback: types.CallbackQuery, state: FSMContext):
    await callback.message.delete()
    await callback.message.answer('Подбор закончен')
    await state.finish()
     
    1. killmator Topic starter
  5. derkown
    derkown Jul 1, 2022 :abizyan: 8,616 Apr 27, 2021
    сойдёт
     
  6. Nodus
    Nodus Jul 1, 2022 Banned 165 Dec 9, 2021
    поработай со строками, получишь уровень среднего девелопа. Да и вместо этих ваших next back будет всего один хандлер
    Python
    async def cb_view_page(call: types.CallbackQuery):

    page = 0

    if "&page=" in call.data:
    page = int(call.data.split("&page=")[-1])

    # some code here
     
    1. killmator Topic starter
      avatarNodus, спасибо за совет, обязательно с этим разберусь:love2:
  7. Humboy13
    Humboy13 Jul 1, 2022 41 Jan 8, 2020
    вот мой простенький пример
    Python
    from aiogram import Bot
    from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
    from aiogram.contrib.fsm_storage.memory import MemoryStorage
    from aiogram.dispatcher import Dispatcher
    from aiogram.utils import executor
    from aiogram.utils.callback_data import CallbackData

    from typing import Collection

    bot = Bot(token="")
    storage = MemoryStorage()
    dp = Dispatcher(bot, storage=storage)

    navigation = CallbackData("navigation", "action", "direction")


    class Pagination:
    def __init__(self, buttons: Collection[InlineKeyboardButton], buttons_on_page: int = 3) -> None:
    self.__buttons = buttons
    self.__buttons_on_page = buttons_on_page
    self.__current_page = 0

    async def update_kb(self) -> InlineKeyboardMarkup:
    markup = InlineKeyboardMarkup()
    from_ = self.__current_page * self.__buttons_on_page
    to_ = (self.__current_page + 1) * self.__buttons_on_page

    prev_button = InlineKeyboardButton("⬅",
    callback_data=navigation.new(action="navigate", direction="previous"))
    next_button = InlineKeyboardButton("➡",
    callback_data=navigation.new(action="navigate", direction="next"))

    for button in self.__buttons[from_:to_]:
    markup.row(button)

    if from_ <= 0:
    return markup.row(next_button)
    elif to_ >= len(self.__buttons):
    return markup.row(prev_button)
    return markup.row(prev_button, next_button)

    async def on_next(self) -> None:
    self.__current_page += 1

    async def on_prev(self) -> None:
    self.__current_page -= 1


    def start_buttons(amount: int = 15) -> Collection[InlineKeyboardButton]:
    return [InlineKeyboardButton(str(i), callback_data=str(i)) for i in range(amount)]


    pagination = Pagination(start_buttons(15), 2)


    @dp.message_handler(commands=["start"])
    async def on_start(message: Message) -> None:
    await message.answer("MENU", reply_markup=await pagination.update_kb())


    @dp.callback_query_handler(navigation.filter(action="navigate", direction="next"))
    async def next_(query: CallbackQuery) -> None:
    await pagination.on_next()
    await query.message.edit_text("MENU", reply_markup=await pagination.update_kb())


    @dp.callback_query_handler(navigation.filter(action="navigate", direction="previous"))
    async def prev_(query: CallbackQuery) -> None:
    await pagination.on_prev()
    await query.message.edit_text("MENU", reply_markup=await pagination.update_kb())


    if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)
     
    1. killmator Topic starter
    2. vinter_man
      avatarHumboy13, Балдёж, спасибо большое. Очень ясный и лаконичный код
  8. DanyByLC
    DanyByLC Aug 7, 2023 0 May 29, 2022
Loading...