Продолжаем скрещивать змей и птиц (или — цирк и фрукт, кому как больше нравится). В предыдущей статье мы научились создавать уведомления, теперь перейдем к не менее востребованным форточкам: формы ввода данных и файловые навигаторы.
Началось с простейшей потребности сделать аналог InputBox'a — окна с полем ввода для текста. В результате этой «простейшей потребности» на свет появилось еще пара полезных плюшек и базовый класс для создания UI-форм.
Тот самый InputBox. Здесь все просто — за основу был взят kivy.uix.textinput.TextInput и повешен на всплывающее окно. Применяем так:
Результат:
Просто. Как и требовалось — в одну строку. Параметром text задаем значение по умолчанию для поля ввода, а если поле нужно пустым — исключаем этот параметр.
Кстати, если в поле ввода нажать «Enter», окно воспримет это как нажатие кнопки «Ok».
Как получить введенные данные? Очень просто — пишем очередной обработчик закрытия окна:
Метод .get_value() возвращает значение элемента размещенного на UI-форме, подробнее об этом здесь.
Метод .is_canceled() возвращает True, если была нажата кнопка «Cancel». Подробнее об этом здесь.
Как заменить стандартные кнопки своими — смотрим здесь.
Финальный аккорд — добавим немного «юзерфрендли» (в случаеunexpected exception пустого поля сообщим пользователю что он об ошибке):
Обратите внимание на место в коде:
Для того, чтобы отменить событие закрытия окна, нужно вернуть True. Не совсем удобно, но именно такого результата ожидает суперкласс.
Тот же XTextInput, тольков профиль для ввода многострочного текста:
Результат:
XNotes является потомком XTextInput и все, что описано выше о XTextInput справедливо для XNotes, за исключением:
Всплывающее окно с kivy.uix.slider.Slider на борту. Употреблять так:
По умолчанию, ползунок двигается в диапазоне [0 (min), 1 (max)], а его текущая позиция (value) на отметке 0.5. При желании эти параметры легко заменяются на другие:
Результат:
Как любому потомку XForm, данному классу также доступен метод .get_value(), которым можно воспользоваться в обработчике события закрытия окна. Помимо этого, класс позволяет обрабатывать изменение положения ползунка «на лету» с помощью события «on_change». Как обычно, опишем обработчик события:
В видео демонстрации показан более «наглядный» пример работы события «on_change». Здесь код обработчика изменяет размеры всплывающего окна.
Данный класс позволяет создать простую форму для авторизации пользователя. Форма имеет поле для ввода логина, поле с маскированием символов для ввода пароля и чекбокс «Login automatically». Данный пример:
Результат:
Для получения данных с формы пишем обработчик события закрытия окна. С помощью метода .get_value() получаем содержимое соответствующего поля:
Что нужно знать о базовом классе?
Хорошо, пробуем написать свою форму:
и смотрим на результат:
Помимо .get_value(id), класс имеет свойство values. Это dict, в котором ключ — id элемента формы, а значение — значение этого элемента. Используя это свойство, можно реализовать обработчик по-другому:
Т.е. окна для выбора файлов\каталогов или для ввода имени сохраняемого файла. Выглядят они приблизительно так:
Создает окно для выбора файла. Пример:
Нужно выбрать несколько файлов? Выбираем несколько. Заодно укажем путь по умолчанию и опишем обработчик для получения списка выбранных файлов:
Класс уже содержит реализацию проверки на пустой выбор и не даст пользователю закрыть окно по кнопке «Open», пока не будет выбран хотя бы один файл. Поэтому в обработчике пишем проверку только на нажатие «Cancel».
И пробуем создать русскую локализацию класса. Простой подменой кнопок здесь не обойтись, придется немного потанцевать с бубном:
Не совсем удобно, но для текущей версии это выход. В версии 0.3.0 будет реализовано больше удобств для локализации.
Окно для ввода имени сохраняемого файла. Используется аналогично, за исключением свойств selection и multiselect — здесь они нам не понадобятся. Вместо них будем использовать:
Пример:
Класс также содержит реализацию проверки на отсутствие текста в поле ввода, так что не заморачиваемся на этот счет.
Окно для выбора каталога. Используется аналогично XFilePopup. Нюанс в том, что при multiselect=False свойство selection будет содержать текущий каталог (т.е. выбираем текущий открытый каталог; это позволяет выбрать корень, при острой необходимости), а при multiselect=True свойство selection содержит список выделенных каталогов.
Подробнее о тонкостях выбора каталога см. ниже.
За основу взят kivy.uix.filechooser.FileChooser — виджет для навигации по файловой системе. Кроме него всплывающее окно содержит следующие элементы:
FileChooser имеет большой список полезных свойств, но в XFilePopup вынесены только свойства «первой необходимости»:
Создадим окно, укажем ему путь и набор кнопок (XFilePopup не имеет собственного набора кнопок). И сразу опишем обработчик для получения результатов:
Обратим внимание на параметр path — значение ему передается в виде unicode string. Это необходимо для корректного отображения имен файлов и каталогов, содержащих не-ASCII символы (например, символы кодировки windows-1251 итд)
В результате получим навигатор, позволяющий выбрать только один файл, без возможности выбора папок (аналог XFileOpen).
И напоследок, пару слов о рамах для форточек
Как видно из иерархии классов, XBase приходится предком всем рассмотренным в статье классам. С некоторыми из его свойств и методов мы уже бегло ознакомились, здесь приведу полный список фич, которые передаются объектно-ориентированным путем:
Также данный класс задает значения по умолчанию некоторым свойствам суперклассов:
Примечание. Данный класс игнорирует свойство content класса Popup.
Потомок Popup и суперкласс для XBase. Создан длятщательной обработки напильником коррекции отображения окон на мобильных девайсах. Его свойства:
Примечание. Применение описанных свойств происходит только в момент отображения окна.
Расширяем фреймворк Kivy пакетом XPopup (Часть 1-я)
Наглядное пособие (видео демонстрация).
Скачать пакет XPopup.
На сегодня все.
Спасибо за внимание и приятного вам кодинга.
Формы ввода данных
Началось с простейшей потребности сделать аналог InputBox'a — окна с полем ввода для текста. В результате этой «простейшей потребности» на свет появилось еще пара полезных плюшек и базовый класс для создания UI-форм.
Класс XTextInput
Тот самый InputBox. Здесь все просто — за основу был взят kivy.uix.textinput.TextInput и повешен на всплывающее окно. Применяем так:
XTextInput(title='Что будем искать?', text='Как пройти в библиотеку?')
Результат:
Просто. Как и требовалось — в одну строку. Параметром text задаем значение по умолчанию для поля ввода, а если поле нужно пустым — исключаем этот параметр.
Кстати, если в поле ввода нажать «Enter», окно воспримет это как нажатие кнопки «Ok».
Как получить введенные данные? Очень просто — пишем очередной обработчик закрытия окна:
def my_callback(instance):
# Если не была нажата кнопка "Cancel"
if not instance.is_canceled():
# Получаем текст из поля ввода
search = instance.get_value()
print(u'Ищем: %s' % search)
XTextInput(title='Что будем искать?', text='Как пройти в библиотеку?',
on_dismiss=my_callback)
Метод .get_value() возвращает значение элемента размещенного на UI-форме, подробнее об этом здесь.
Метод .is_canceled() возвращает True, если была нажата кнопка «Cancel». Подробнее об этом здесь.
Как заменить стандартные кнопки своими — смотрим здесь.
Финальный аккорд — добавим немного «юзерфрендли» (в случае
def my_callback(instance):
# Если не была нажата кнопка "Cancel"
if not instance.is_canceled():
# Получаем текст из поля ввода
search = instance.get_value()
# Поле ввода пусто
if not search:
# Сообщим пользователю об ошибке
XError(text='Вы так и не сказали, что будем искать')
# Запрещаем закрывать окно
return True
print(u'Ищем: %s' % search)
XTextInput(title='Что будем искать?', on_dismiss=my_callback)
Обратите внимание на место в коде:
# Запрещаем закрывать окно
return True
Для того, чтобы отменить событие закрытия окна, нужно вернуть True. Не совсем удобно, но именно такого результата ожидает суперкласс.
Класс XNotes
Тот же XTextInput, только
XNotes(title='Заметки', text='Строка\nДругая строка...\nЕще одна')
Результат:
XNotes является потомком XTextInput и все, что описано выше о XTextInput справедливо для XNotes, за исключением:
- нажатие «Enter» в поле ввода выполняет переход на новую строку.
- параметр text ожидает на входе строку, многострочность достигается путем добавления "\n".
Класс XSlider
Всплывающее окно с kivy.uix.slider.Slider на борту. Употреблять так:
XSlider(title='Громкость', buttons=['Закрыть'])
По умолчанию, ползунок двигается в диапазоне [0 (min), 1 (max)], а его текущая позиция (value) на отметке 0.5. При желании эти параметры легко заменяются на другие:
XSlider(title='Громкость, dB', buttons=['Закрыть'], min=-100, max=12, value=-10)
Результат:
Как любому потомку XForm, данному классу также доступен метод .get_value(), которым можно воспользоваться в обработчике события закрытия окна. Помимо этого, класс позволяет обрабатывать изменение положения ползунка «на лету» с помощью события «on_change». Как обычно, опишем обработчик события:
def volume_change(instance, value):
instance.title = 'Громкость: %0.0f' % (value * 100)
XSlider(title='Громкость', buttons=['Закрыть'], on_change=volume_change)
В видео демонстрации показан более «наглядный» пример работы события «on_change». Здесь код обработчика изменяет размеры всплывающего окна.
Класс XAuthorization
Данный класс позволяет создать простую форму для авторизации пользователя. Форма имеет поле для ввода логина, поле с маскированием символов для ввода пароля и чекбокс «Login automatically». Данный пример:
XAuthorization()
создаст пустую форму авторизации. Заполнить поля можно с помощью параметров: login, password и autologin:XAuthorization(login='login', password='password', autologin=True)
Результат:
Для получения данных с формы пишем обработчик события закрытия окна. С помощью метода .get_value() получаем содержимое соответствующего поля:
def my_callback(instance):
if not instance.is_canceled():
login = instance.get_value('login')
password = instance.get_value('password')
autologin = instance.get_value('autologin')
print('LOGIN: %s, PASS: %s, AUTO: %s' % (login, password, autologin))
XAuthorization(login='login', password='password', autologin=True,
on_dismiss=my_callback)
Класс XForm
Что нужно знать о базовом классе?
- Базовый класс имеет метод .get_value(id), который ищет на форме элемент с указанным id и возвращает его значение. Параметр необязательный, если его не указать — метод возьмет с формы 1-й элемент, у которого задан id и вернет его значение. Данная реализация поддерживает получение значений элементов: TextInput, Switch, CheckBox, Slider.
- Класс имеет абстрактный метод ._get_form(), результатом работы которого должен быть контент формы.
- Класс задает следующий набор кнопок по умолчанию: «Ok», «Cancel».
Хорошо, пробуем написать свою форму:
class MyForm(XForm):
def _get_form(self):
# Создаем контейнер формы
layout = BoxLayout()
# Добавим текст без id (значение этого элемента не нужно)
layout.add_widget(Label(text='Show must go'))
# Добавим чекбокс с id (значение этого элемента пригодится)
layout.add_widget(Switch(id='main_switch', active=True))
# Возвращаем контейнер
return layout
def my_callback(instance):
# обработчик закрытия окна
if not instance.is_canceled():
print('Switch value: ' + str(instance.get_value('main_switch')))
MyForm(title='Party switch', on_dismiss=my_callback)
и смотрим на результат:
Помимо .get_value(id), класс имеет свойство values. Это dict, в котором ключ — id элемента формы, а значение — значение этого элемента. Используя это свойство, можно реализовать обработчик по-другому:
def my_callback(instance):
# обработчик закрытия окна
if not instance.is_canceled():
print('Switch value: ' + str(instance.values['main_switch']))
Файловые навигаторы
Т.е. окна для выбора файлов\каталогов или для ввода имени сохраняемого файла. Выглядят они приблизительно так:
Класс XFileOpen
Создает окно для выбора файла. Пример:
XFileOpen()
Нужно выбрать несколько файлов? Выбираем несколько. Заодно укажем путь по умолчанию и опишем обработчик для получения списка выбранных файлов:
def my_callback(instance):
if not instance.is_canceled():
print(u'Path: ' + instance.path)
print(u'Selection: ' + str(instance.selection))
XFileOpen(multiselect=True, path=u'c:\python27', on_dismiss=my_callback)
Класс уже содержит реализацию проверки на пустой выбор и не даст пользователю закрыть окно по кнопке «Open», пока не будет выбран хотя бы один файл. Поэтому в обработчике пишем проверку только на нажатие «Cancel».
И пробуем создать русскую локализацию класса. Простой подменой кнопок здесь не обойтись, придется немного потанцевать с бубном:
class XFileOpenRU(XFileOpen):
title = StringProperty('Открытие файла')
# константа используется в коде проверки на пустой выбор
BUTTON_OPEN = 'Открыть'
# теперь метод .is_canceled() правильно реагирует на новое имя кнопки
BUTTON_CANCEL = 'Отмена'
# меняем сообщение об ошибке
TXT_ERROR_SELECTION = 'Может, сначала выберем файл?'
# переопределяем набор кнопок для использования новых констант
buttons = ListProperty([BUTTON_OPEN, BUTTON_CANCEL])
XFileOpenRU()
Не совсем удобно, но для текущей версии это выход. В версии 0.3.0 будет реализовано больше удобств для локализации.
Класс XFileSave
Окно для ввода имени сохраняемого файла. Используется аналогично, за исключением свойств selection и multiselect — здесь они нам не понадобятся. Вместо них будем использовать:
- filename — привязано к полю ввода имени файла, можно задать значение по умолчанию или считать введенный текст;
- .get_full_name() — метод, возвращающий путь с именем файла.
Пример:
def my_callback(instance):
if not instance.is_canceled():
# только путь
print(u'Path: ' + instance.path)
# только имя файла
print(u'Filename: ' + instance.filename)
# путь с именем файла
print(u'Full name: ' + instance.get_full_name())
popup = XFileSave(filename='file_to_save.txt', on_dismiss=my_callback)
Класс также содержит реализацию проверки на отсутствие текста в поле ввода, так что не заморачиваемся на этот счет.
Класс XFolder
Окно для выбора каталога. Используется аналогично XFilePopup. Нюанс в том, что при multiselect=False свойство selection будет содержать текущий каталог (т.е. выбираем текущий открытый каталог; это позволяет выбрать корень, при острой необходимости), а при multiselect=True свойство selection содержит список выделенных каталогов.
Подробнее о тонкостях выбора каталога см. ниже.
Класс XFilePopup
За основу взят kivy.uix.filechooser.FileChooser — виджет для навигации по файловой системе. Кроме него всплывающее окно содержит следующие элементы:
- Кнопка «Icons» — включает режим отображения содержимого в виде иконок;
- Кнопка «List» — включает режим отображения содержимого в виде списка;
- Кнопка «New folder» — создает новый каталог;
- Метка, отображающая текущий каталог.
FileChooser имеет большой список полезных свойств, но в XFilePopup вынесены только свойства «первой необходимости»:
- path — каталог, содержимое которого отобразится при создании окна; по умолчанию — '/'. Меняет значение при смене каталога;
- multiselect — разрешить/запретить выбор нескольких элементов; по умолчанию — False;
- dirselect — разрешить/запретить выбор каталогов; по умолчанию — False. Важно: при dirselect=False открытие каталога происходит в один клик; при dirselect=True — одинарный клик помечает каталог выбранным, а открытие выполняется двойным кликом (что не совсем удобно на мобильных девайсах);
- selection — список, содержащий выбранные элементы;
- browser — объект класса FileChooser, «вынесен наружу» для возможности воспользоваться его остальными свойствами.
Создадим окно, укажем ему путь и набор кнопок (XFilePopup не имеет собственного набора кнопок). И сразу опишем обработчик для получения результатов:
def my_callback(instance):
print(u'Path: ' + instance.path)
print(u'Selection: ' + str(instance.selection))
XFilePopup(title='Файловый навигатор', buttons=['Select', 'Close'],
path=u'c:/python27', on_dismiss=my_callback)
Обратим внимание на параметр path — значение ему передается в виде unicode string. Это необходимо для корректного отображения имен файлов и каталогов, содержащих не-ASCII символы (например, символы кодировки windows-1251 итд)
В результате получим навигатор, позволяющий выбрать только один файл, без возможности выбора папок (аналог XFileOpen).
3 2 кита
И напоследок, пару слов о рамах для форточек
Класс XBase
Как видно из иерархии классов, XBase приходится предком всем рассмотренным в статье классам. С некоторыми из его свойств и методов мы уже бегло ознакомились, здесь приведу полный список фич, которые передаются объектно-ориентированным путем:
- auto_open — boolean свойство; если True, то при создании экземпляра класса окно будет отображатся автоматически. Иначе — для отображения окна у экземпляра нужно вызвать метод .open(). По умолчанию — True.
- buttons — list свойство, определяющее набор управляющих кнопок всплывающего окна. По умолчанию — [].
- button_pressed — string свойство, содержит имя нажатой управляющей кнопки. Доступно в обработчике события on_dismiss.
- .is_canceled() — метод, возвращающий True, если имя нажатой кнопки = XBase.BUTTON_CANCEL.
- ._get_body() — абстрактный метод, результатом которого должен быть контент окна.
Также данный класс задает значения по умолчанию некоторым свойствам суперклассов:
- min_width=300dp, min_height=150dp, fit_to_window=True — свойства из XPopup, об этом — ниже;
- size_hint=(.6, .3) — свойство из Popup, задает относительные размеры окна;
- auto_dismiss=False — свойство из Popup, запрещает закрытие окна по клику в любой области интерфейса за пределами самого окна.
Примечание. Данный класс игнорирует свойство content класса Popup.
Класс XPopup
Потомок Popup и суперкласс для XBase. Создан для
- min_width и min_height — минимальные ширина и высота окна, значения по умолчанию отсутствуют. Работают в паре с size_hint. Суть: при заданных min_width и/или min_height происходит коррекция значений size_hint так, чтобы размеры окна были не меньше допустимых минимальных значений.
- fit_to_window — boolean свойство «вместить в окно», по умолчанию — False. Работает в паре с size. Суть: при fit_to_window=True происходит коррекция значений size так, чтобы размеры всплывающего окна были не больше размеров окна приложения.
Примечание. Применение описанных свойств происходит только в момент отображения окна.
Ссылки
Расширяем фреймворк Kivy пакетом XPopup (Часть 1-я)
Наглядное пособие (видео демонстрация).
Скачать пакет XPopup.
На сегодня все.
Спасибо за внимание и приятного вам кодинга.
Поделиться с друзьями
Myrddin
Круто! Спасибо за отличный набор компонентов. Сейчас как раз выбираю графический фреймворк для питона. Смотрю в сторону Qt, wxPython и Kivy.
Насколько я понимаю, у kivy главный недостаток — это существенное время первого запуска приложения. Возможно ли как-то снизить его?
ophermit
Никогда не задавался этим вопросом, потому что не наблюдал особых неудобств. «Холодный» старт kivy-приложения на 1-3 секунды больше «холодного» старта python-интерпретатора.
В плане выбора фреймворка — проблематично сказать, чем Kivy лучше остальных. Qt и wxPython я детально не рассматривал. Отплясывай от потребностей :) Если есть потребность собирать .apk под android — тогда только Kivy.