Одно из главных преимуществ создания приложения с Tkinter в том, что с его помощью очень просто настроить интерфейс всего в несколько строк. И если программа становится сложнее, то и сложнее логически разделять ее на части, а организованная структура помогает сохранять код в чистом виде.
Простой пример
Возьмем в качестве примера следующую программу:
from tkinter import * root = Tk()
btn = Button(root, text=»Нажми!»)
btn.config(command=lambda: print(«Привет, Tkinter!»))
btn.pack(padx=120, pady=30)
root.title(«Мое приложение Tkinter»)
root.mainloop()
Она создает окно с кнопкой, которая выводит Привет, Tkinter! каждый раз при нажатии. Кнопка расположена с внутренним отступом 120px по горизонтальной оси и 30px – по вертикальной. Последняя строка запускает основной цикл, который обрабатывает все пользовательские события и обновляет интерфейс до закрытия основного окна.
Vkontakte BOT (vk_api python) [2] | Клавиатура, кнопочки.
Программу можно запустить, чтобы убедиться, что она работает. Все переменные определяются в глобальном пространстве имен, и чем больше виджетов добавляется, тем сложнее разобраться в том, какие части они используют.
Wildcard-импорты ( from … import * ) считаются плохой практикой, поскольку они загрязняют глобальное пространство имен. Здесь они используются для иллюстрации анти-паттерна, который часто встречается в примерах онлайн.
Эти проблемы настройки решаются с помощью базовых техник объектно-ориентированного программирования, что считается хорошей практикой для любых типов программ на Python.
Правильный пример
Чтобы улучшить модуль простой программы, стоит определить несколько классов, которые станут обертками вокруг глобальных переменных:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.btn = tk.Button(self, text=»Нажми!»,
command=self.say_hello)
self.btn.pack(padx=120, pady=30)
def say_hello(self):
print(«Привет, Tkinter!»)
if __name__ == «__main__»:
app = App()
app.title(«Мое приложение Tkinter»)
app.mainloop()
Теперь каждая переменная хранится в конкретной области видимости, включая функцию command , которая находится в отдельном методе.
Как работает это приложение?
Во-первых нужно заменить wildcard-импорт на импорт в формате import … as для лучшего контроля над глобальным пространством имен.
Затем класс App определяется как подкласс Tk , который теперь ссылается на пространство имен tk . Для правильной инициализации базового класса, вызывается метод __init__() класса Tk с помощью встроенной функции super() . За это отвечают следующие строки:
class App(tk.Tk):
def __init__(self):
super().__init__()
Генерация и отправка простой клавиатуры. Курс «Создание чат-бота ВКонтакте на python». Часть 5
# .
Теперь есть ссылка на экземпляр App с переменной self . Так что виджет кнопки будет добавлен как атрибут класса.
Это может казаться излишним для такой простой программы, но подобный рефакторинг помогает работать с каждой отдельной частью. Создание кнопки отделено от обратного вызова, которые исполняется при нажатии. А генерация приложения перемещена в if __name__ == «main» , что является стандартной практикой для исполняемых скриптов в Python.
Такой же принцип будет использовать в примерах и дальше, поэтому его можно взять как шаблон-стартовая точка для крупных приложений.
Дополнение о структуре приложения
Класс Tk вынесен в отдельный класс в примере, но распространенной практикой считается выделять так же другие классы виджетов. Это делается для воссоздания тех же инструкций, которые были до рефакторинга.
Однако может быть более удобно разделять классы Frame или Toplevel особенно для больших программ, где, например, есть несколько окон. Это все потому что у приложения Tkinter должен быть один экземпляр Tk , а система создает их автоматически при создании экземпляра виджета до создания экземпляра самого Tk .
Помните, что это не влияет на структуру класса App , поскольку у всех классов виджетов есть метод mainloop , который запускает основной цикл Tk .
Работа с кнопками
Виджеты кнопок представляют собой кликабельные элементы графического интерфейса приложений. Они обычно используют текст или изображение, указывающие на то, какое действие будет выполнено при нажатии. Tkinter позволяет легко настраивать их функциональность с помощью стандартных настроек класса виджета Button .
Как создать кнопку
Следующий блок содержит кнопку с изображением, которая выключается при нажатии, а также список кнопок с разными типами анимации после нажатия:
import tkinter as tk
RELIEFS = [tk.SUNKEN, tk.RAISED, tk.GROOVE, tk.RIDGE, tk.FLAT]
class ButtonsApp(tk.Tk):
def __init__(self):
super().__init__()
self.img = tk.PhotoImage(file=»python.gif»)
self.btn = tk.Button(self, text=»Кнопка с изображением»,
image=self.img, compound=tk.LEFT,
command=self.disable_btn)
self.btns = [self.create_btn(r) for r in RELIEFS]
self.btn.pack()
for btn in self.btns:
btn.pack(padx=10, pady=10, side=tk.LEFT)
def create_btn(self, relief):
return tk.Button(self, text=relief, relief=relief)
def disable_btn(self):
self.btn.config(state=tk.DISABLED)
if __name__ == «__main__»:
app = ButtonsApp()
app.mainloop()
Цель программы — показать разные варианты настройки, которые могут быть использованы при создании виджета кнопки.
После выполнения кода выше, возвращается следующее:
Простейший способ создания экземпляра Button — использование параметра text для настройки метки кнопки и command , который ссылается на вызываемую функцию при нажатии кнопки.
В этом примере также добавляется PhotoImage с помощью параметра image , который имеет приоритет над строкой text . Этот параметр используется для объединения изображения и текста на одной кнопке, определяя местоположение, где будет находиться картинка. Он принимает следующие константы: CENTER, BOTTOM, LEFT, RIGHT и TOP.
Второй ряд кнопок создается с помощью сгенерированного списка и списка значений RELIEF . Метка каждой кнопки соответствует константе, так что можно заметить разницу во внешнем виде.
Для сохранения ссылки на экземпляр PhotoImage использовался атрибут, хотя его и нет вне метода __init__ . Причина в том, что изображения удаляются при сборке мусора. Это и происходит, если объявить их в качестве локальных переменных.
Для избежания этого нужно помнить о сохранении ссылки на каждый объект PhotoImage до тех пор, пока окно, где он показывается, не закрыто.
Следующий урок: Работа с текстом (в разработке)
Источник: pythonru.com
Как правильно основать клавиатуру/кнопки(vk api) | Python?
Подскажите, пожалуйста, работаю с клавиатурой (keyboard vk_api) и хотелось бы основать систему:
игрок вводит определённую команду — к примеру открываются кнопки «1» «2»
затем вводит команду «2»(нажимая на предыдущую кнопку) — и открываются другие кнопки «3» «4».
Как можно сделать?
Программирование Python
Danil Gazizullin
17 декабря 2021 ·
Айтишник, back-end, Python-Developers (html,css,js,python,c#,c). Щедрый бог, ищу работу. · 1 мар 2022
Чтоб выполнить такое задание можешь использовать уже готовые клавиатуры, по другому будет сложно, или если нужно генерировать то помогу функцией
def get_but(text: str, color: str) -> Dict(): return < «action»: < «type»: «text», «payload»: «», «label»: f»» >, «color»: f»» >
Возращает кнопку в формате json
keyboard1 =
пример создания самой клавиатуры.
Но я бы посоветовал сменить vk_api на vkbottle пока не написал слишком много кода вот ссылка VKBottle
Источник: yandex.ru
Делаем кнопки в телеграмме на python чать 2
А если хотите обе кнопки в ряд, то уберите row_width=1 (тогда будет использоваться значение по умолчанию 3).
Напишем хэндлер, который по команде /random будет отправлять сообщение с колбэк-кнопкой:
Но как же обработать нажатие? Если раньше мы использовали message_handler для обработки входящих сообщений, то теперь будем использовать callback_query_handler для обработки колбэков.
Ориентироваться будем на «значение» кнопки, т.е. на её data:
Несмотря на то, что параметр кнопки callback_data, а значение data лежит в одноимённом поле data объекта CallbackQuery , собственный фильтр aiogram называется text.
Ой, а что это за часики? Оказывается, сервер Telegram ждёт от нас подтверждения о доставке колбэка, иначе в течение 30 секунд будет показывать специальную иконку.
Чтобы скрыть часики, нужно вызвать метод answer() у колбэка (или использовать метод API answer_callback_query()).
В общем случае, в метод answer() можно ничего не передавать, но можно вызвать специальное окошко (всплывающее сверху или поверх экрана):
В функции send_random_value мы вызывали метод answer() не у message, а у call.message.
Это связано с тем, что колбэк-хэндлеры работают не с сообщениями (тип Message ), а с колбэками (тип CallbackQuery ), у которого другие поля, и само сообщение — всего лишь его часть.
Учтите также, что message — это сообщение, к которому была прицеплена кнопка (т.е. отправитель такого сообщения — сам бот).
Если хотите узнать, кто нажал на кнопку, смотрите поле from (в вашем коде это будет call.from_user, т.к. слово from зарезервировано в Python)
Перейдём к примеру посложнее. Пусть пользователю предлагается сообщение с числом 0, а внизу три кнопки: +1, -1 и Подтвердить.
Первыми двумя он может редактировать число, а последняя удаляет всю клавиатуру, фиксируя изменения.
Хранить значения будем в памяти в словаре (про конечные автоматы поговорим как-нибудь в другой раз).
И, казалось бы, всё работает:
Но теперь представим, что ушлый пользователь сделал следующее: вызвал команду /numbers (значение 0), увеличил значение до 1, снова вызвал /numbers (значение сбросилось до 0) и отредактировал нажал кнопку «+1» на первом сообщении.
Что произойдёт?
Бот по-честному отправит запрос на редактирование текста со значением 1, но т.к. на том сообщении уже стоит цифра 1, то Bot API вернёт ошибку, что старый и новый тексты совпадают, а бот словит исключение: aiogram.utils.exceptions.MessageNotModified: Message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message
С этой ошибкой вы, скорее всего, будете поначалу часто сталкиваться, пытаясь редактировать сообщения.
Но, в действительности, решается проблема очень просто: мы проигнорируем исключение MessageNotModified.
# from aiogram.utils.exceptions import MessageNotModified # from contextlib import suppress async def update_num_text(message: types.Message, new_value: int): with suppress(MessageNotModified): await message.edit_text(f»Укажите число: «, reply_markup=get_keyboard())
Если теперь вы попробуете повторить пример выше, то указанное исключение в этом блоке кода бот просто-напросто проигнорирует.
Фабрика колбэков
В aiogram существует т.н. фабрика колбэков. Вы создаёте объект CallbackData, указываете ему префикс и произвольное количество доп. аргументов, которые в дальнейшем указываете при создании колбэка для кнопки.
Например, рассмотрим следующий объект:
# from aiogram.utils.callback_data import CallbackData cb= CallbackData(«post», «id», «action»)
Тогда при создании кнопки вам надо указать её параметры так:
Python:
button = types.InlineKeyboardButton( text=»Лайкнуть», callback_data=cb.new(id=5, action=»like») )
В примере выше в кнопку запишется callback_data, равный post:5:like, а хэндлер на префикс post будет выглядеть так:
В предыдущем примере с числами мы грамотно выбрали callback_data, поэтому смогли легко запихнуть все обработчики в один хэндлер.
Но можно логически разнести обработку инкремента и декремента от обработки нажатия на кнопку «Подтвердить».
Для этого в фильтре фабрики можно указать желаемые значения какого-либо параметра. Давайте перепишем наш пример с использованием фабрики:
На этом глава про кнопки окончена, но про некоторые других их виды мы поговорим в следующих главах.
Источник: teletype.in