Kivy Python
Kivy это фреймворк на Python с открытым исходным кодом для разработки кроссплатформенных приложений.
Нашел этот фреймворк, когда понадобилось написать мобильное приложения для получение данных по API с сайта на Django, вроде показался не очень сложным, а главное позволил создать приложение для Android на Python.
Это не учебник и не подробная статья по Kivy, а просто пример создания приложения уровня HelloWorld.
Для начала установим Kivy, согласно официальной документации через pip это делается командой:
pip install kivy[base]
Первая программа на фреймворке Kivy
После установки, проверим работоспособность kivy создав простое первое приложение, которое выведет нам Привет мир!
Создадим файл hello.py со следующим содержимым:
from kivy.app import App
from kivy.uix.label import Label
class MainApp(App):
def build(self):
label = Label(text='Привет мир!')
return label
if __name__ == '__main__':
app = MainApp()
app.run()
Запускаем и видим наше приложение:
Каждому приложению Kivy требуется создать подкласс App и переопределить метод build(), что мы и сделали. Сюда мы поместили код, который создает виджет Label с переданным значением text.
В Kivy все элементы располагаются на layout и чтобы вывести несколько элементов (например слова «привет» и «мир» мы хотим разместить на разных виджетах Label), нам нужно расположить их на нем.
Всего существует 8 видов лайаутов, о них можно почитать в официальной документации: https://kivy.org/doc/stable/gettingstarted/layouts.html
Для нашего примера будем использовать BoxLayout, в нем все элементы располагаются друг за другом при горизонтальной ориентации или друг под другом при вертикальной.
Изменим метод build чтобы он возвращал нам не один элемент интерфейса, а слой с несколькими элементами:
def build(self):
layout = BoxLayout()
label1 = Label(text='Привет')
label2 = Label(text='мир!')
layout.add_widget(label1)
layout.add_widget(label2)
return layout
Не забудем импортировать BoxLayout
from kivy.uix.boxlayout import BoxLayout
Теперь запустим и увидим нужный результат:
Все работает, но не видно где заканчивается один Label и начинается второй. Например, я хочу поменять фон и работать с позиционированием элементов, для этого в киви существует язык разметки.
Сделаем отдельный файл с этой разметкой, он должен иметь расширение kv, по умолчанию метод run() будет искать с файл с именем нашего класса без App, т.е. в нашем случае main.kv
Перепишем пример выше, сначала код файла main.kv:
<MainWidget>:
Label:
text: 'Привет'
Label:
text: 'Мир'
Теперь изменим код hello.py на:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class MainWidget(BoxLayout):
pass
class MainApp(App):
def build(self):
return MainWidget()
if __name__ == '__main__':
app = MainApp()
app.run()
Запускаем скрипт и мы должны увидеть все тоже самое, если так, то ничего не сломалось и можно продолжить.
Начнем доработку внешнего вида, для этого поменяем файл main.kv. Во первых сделаем разные цвета для наших Label и отделим их друг от друга:
<MainWidget>:
orientation: 'vertical'
padding: 20
spacing: 20
Label:
markup: True
text: '[color=000000]Привет[/color]'
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Мир'
canvas.before:
Color:
rgba: 1, .5, 0, 1
Rectangle:
pos: self.pos
size: self.size
Проверяем:
Усложняем программу
Теперь сделаем программу чуть сложнее чем Helloworld, сделаем чтобы мы вводили в нее свое имя и она с нами здоровалась.
Она должна выглядеть вот так:
Сверху картинка, потом поле ввода, потом надпись, потом кнопка.
Файл шаблона (main.kv) у меня получился таким:
<MainWidget>:
orientation: 'vertical'
padding: 20
spacing: 20
Image:
source: 'hello.png'
TextInput:
multiline: False
size_hint: (.5, None)
pos_hint:{"center_x":0.5, "top":1}
height: 50
font_size: 30
Label:
font_size: 30
text: 'Напишите как вас зовут'
Button:
font_size: 30
text: 'Поздороваться'
size_hint: (.5, None)
pos_hint:{"center_x":0.5, "top":1}
hello.png — это файл с картинкой с надписью hello, в моем случае он лежит в корне проекта
Теперь осталось сделать чтобы программа выполняла свою функцию и здоровалась с нами по нажатию кнопки «Поздороваться».
Сначала добавим в класс MainWidget добавим метод say_hello():
class MainWidget(BoxLayout):
def say_hello(self):
print('тест кнопки')
Он будет вызываться по нажатию кнопки. Для того чтобы кнопка реагировала на нажатие, добавим ей атрибут on_press, который будет вызывать метод say_hello():
Button:
font_size: 30
text: 'Поздороваться'
size_hint: (.5, None)
pos_hint:{"center_x":0.5, "top":1}
on_press: root.say_hello()
Если сейчас запустить программу и нажать на кнопку «Поздороваться», то в консоли мы получим сообщение «тест кнопки».
Если так, то пока все работает правильно
Дальше нужно сделать, чтобы в Label менялся текст на тот, который введен в виджете TextInput.
Для этого нам нужно получить доступ к свойству text этих виджетов.
Для этого импортируем класс ObjectProperty и создадим 2 экземпляра этого класса:
from kivy.properties import ObjectProperty
class MainWidget(BoxLayout):
hello_label = ObjectProperty()
name_input = ObjectProperty()
def say_hello(self):
...
Теперь откроем файл main.kv и добавим индефикаторы для виджетов Label и TextInput, чтобы на них можно было ссылаться из других частей KV файла.
TextInput:
id: name
Label:
id: hello
Теперь установим эти индефикаторы в значения свойств hello_label и name_input, которые мы определили в методе say_hello():
<MainWidget>:
orientation: 'vertical'
padding: 20
spacing: 20
name_input: name
hello_label: hello
...
Теперь мы можем получить доступ к свойству text этих виджетов, изменим методе say_hello():
def say_hello(self):
self.hello_label.text = 'Привет ' + self.name_input.text
Собственно все, можно запустить программу и проверить, все должно работать.
Весь код файлов есть в репозитории на гитхабе https://github.com/alexandrtretyakov/kivy