Read the book: «Разработка кроссплатформенных мобильных и настольных приложений на Python. Практическое пособие», page 6

Font::

2.6. Правила работы с виджетами в Kivy

2.6.1. Задание размеров и положения виджетов в окне приложения

Виджеты в Kivy по умолчанию заполняют все окно приложения и располагаются в его центре. Однако они имеют еще ряд свойств, благодаря которым, виджету можно задать размер и поместить в разные области окна приложения.

Рассмотрим на примере кнопки Button, как можно задать ей размер и расположить в разных местах главного экрана. Создадим файл с именем Button1.py и напишем в нем следующий код (листинг 2.42).

Листинг 2.42. Задание параметров виджету Button – размер и положение (модуль Button1.py)

# модуль Button1.py

from kivy. app import App

from kivy.lang import Builder

KV = «»»

Button:

…… text: «Это кнопка»

…… size_hint:.5,.5

…… # – — – — – — – — – —

…… #size_hint:.8,.5

…… #size_hint:.5,.8

…… pos_hint: {’center_x’:.5, ’center_y’:.5}

…… # – — – — – — – — – — – — – — – — – — – — – —

…… #size_hint:.2,.1

…… #pos_hint: {’center_x’:.15, ’center_y’:.5}

…… #pos_hint: {’center_x’:.85, ’center_y’:.5}

…… #pos_hint: {’center_x’:.5, ’center_y’:.15}

…… #pos_hint: {’center_x’:.5, ’center_y’:.85}

«»»

class MainApp (App):

…… def build (self):

…… …… return Builder. load_string (KV)

MainApp().run ()

Здесь в текстовой строке KV создан виджет – Button (кнопка). Для данного виджета заданы следующие свойства:

– text – надпись на кнопке

– size_hint – размер кнопки;

– pos_hint – положение кнопки в окне приложения.

Если с надписью на кнопке все понятно (свойству text присваивается значение «Это кнопка»). То какой смысл имею следующие два свойства кнопки и их параметры (size_hint и pos_hint). Разберемся с этим вопросом.

Пока рассмотрим две рабочие строки (на которых нет знака комментария «#»):

– size_hint:.5,.5;

– pos_hint: {’center_x’:.5, ’center_y’:.5}.

Свойство кнопки size_hint определяет ее размер по горизонтали (ширина – x) и вертикали (высота -y). Но это не абсолютный, а относительный размер. Если принять размер окна приложения за единицу – 1 (или за 100%), то размер кнопки в нашем случае будет составлять 0.5 (или 50%) от размера окна по ширине и по высоте.

Свойство кнопки pos_hint определяет ее положение в окне приложения, но так же не в абсолютных, а в относительных единицах. По аналогии, если принять размер окна приложения за единицу – 1 (или за 100%), то в этом примере положение центра кнопки будет расположено в точке, составляющей 0.5 (или 50%) от размера окна по горизонтали (по оси «x»), и 0.5 (или 50%) от размера окна по вертикали (по оси «y»).

После запуска данного приложения получим следующий результат (рис.2.32).

Рис. 2.32. Окно приложения Button1.py с кнопкой в центре окна


Вместо положения центра элемента, можно указать положение его левого нижнего угла. Для этого вместо параметров {’center_x’:.5, ’center_y’:.5}, нужно указать {’x’:.5, ’y’:.5}.

Создадим файл с именем Button1_1.py и напишем в нем следующий код (листинг 2.43).

Листинг 2.43. Задание параметров виджету Button – размер и положение (модуль Button1_1.py)

# модуль Button1_1.py

from kivy. app import App

from kivy.lang import Builder

KV = «»»

Button:

…… text: «Это кнопка»

…… size_hint:.5,.5

…… pos_hint: {’x’:.5, ’y’:.5}

«»»

class MainApp (App):

…… def build (self):

…… …… return Builder. load_string (KV)

MainApp().run ()

В результате его выполнения получим следующий результат (рис.2.33).


Рис. 2.33. Окно приложения Button1_1.py с кнопкой (левый нижний угол в центре окна)


Почему в Kivy задаются не абсолютные, а относительные размеры и положение виджетов? Это обеспечивает автоматическую расстановку виджетов в окне приложения, при его запуске на разных устройствах с различным размером и разрешением экранов. При этом будут сохранены все пропорции между размерами и расположением виджетов. Таким образом, программисту не нужно адаптировать приложение для различных устройств. Интерфейс будет корректно выглядеть и на смартфоне, и на планшете, и на настольном компьютере. Однако, если мы планируем создавать приложения для мобильных устройств, то интерфейс пользователя необходимо строить с учетом пропорции и размеров экранов мобильных устройств.

Теперь поэкспериментируем с закомментированными строками. Попробуем изменить размеры кнопки, для этого достаточно переназначить значения свойства size_hint (закомментированные строки):

#size_hint:.8,.5

#size_hint:.5,.8

В первой задали размер кнопки по горизонтали – 0.8, во второй размер кнопки по вертикали – 0.8. Запусти приложение, поочередно меняя комментарии в этих строках. Результаты работы программы представлены на рис. 2.34.


Рис. 2.34. Окно приложения Button1.py при разных параметрах размера кнопки


Итак, на примере кнопки (Button) мы показали, как в Kivy с помощью относительных параметров можно задавать размеры виджета.

Теперь путем настройки свойств кнопки изменим ее положение в окне приложения. Для этого достаточно изменить свойство pos_hint.

Следует иметь в виду, что в KV началом координат (x, y) является левый нижний угол окна приложения. Уменьшим размер кнопки (size_hint:.2,.1) поместим ее в разные места окна приложения, для чего будем снимать комментарии со следующих строк программы:

#size_hint:.2,.1

#pos_hint: {’center_x’:.15, ’center_y’:.5}

#pos_hint: {’center_x’:.85, ’center_y’:.5}

#pos_hint: {’center_x’:.5, ’center_y’:.15}

#pos_hint: {’center_x’:.5, ’center_y’:.85}

Запустим приложение несколько раз, поочередно меняя комментарии в этих строках, и посмотрим на результаты (рис.2.35):


Рис. 2.35. Положение кнопки в различных частях окна приложения


При этом в Kivy имеется возможность задавать не только относительные, но и абсолютные значения параметров. Для этого используются следующие свойства:

– size_hint: None, None – отменить использование автоматической перерисовки элемента (подгонку под размер родительского виджета);

– size – абсолютный размер элемента в пикселах, например, 150, 50 (150 – ширина элемента, 50 – высота элемента);

– pos – абсолютная позиция элемента в окне приложения в пикселах, например, 140, 40 (140 – координата по оси x, 40 – координата по оси y).

Рассмотрим на примере кнопки Button, как можно задать ей абсолютный размер и расположить в указанное место экрана. Создадим файл с именем Button2.py и напишем в нем следующий код (листинг 2.44).

Листинг 2.44. Задание абсолютных параметров виджету Button – размер и положение (модуль Button2.py)

# модуль Button2.py

from kivy. app import App

from kivy.lang import Builder

KV = «»»

Button:

……text: «Кнопка»

…… size_hint: None, None

…… size: 150, 50

…… pos: 100, 50

«»»

class MainApp (App):

…… def build (self):

…… …… return Builder. load_string (KV)

MainApp().run ()

В этой программе мы создали кнопку Button и задали ей абсолютные размеры ширина – 150 пикселей, высота – 50 пикселей, и поместили ее в следующие координаты окна (x= 100, y=50). Кроме того, в строке «size_hint: None, None» мы отменили автоматическое растягивание кнопки в размеры окна приложения.

Примечание.

В приложениях на Kivy нулевой координатой окна приложения (x=0, y=0) является левый нижний угол.

После запуска приложения получим следующий результат (рис.2.36).


Рис. 2.36. Использование абсолютные значений параметров для задания размера и положения элемента в окне приложения


Итак, мы разобрались с очень важной частью использования Kivy для разработки интерфейса – заданием размеров и позиционирования визуальных элементов на основе относительных и абсолютных параметров.

Подводя итог, напомним, какие свойства используются для задания размеров и положения виджетов:

– text – надпись на элементе;

– size_hint – относительный размер элемента (например, size_hint:.5,.5);

– pos_hint – относительное положение элемента в окне приложения (например, центра – pos_hint: {’center_x’:.5, ’center_y’:.5} или левого нижнего угла – pos_hint: {’x’:.5, ’y’:.5}).

– size_hint: None, None – отменить использование автоматической перерисовки элемента (подгонку под размер родительского виджета);

– size – абсолютный размер элемента в пикселах, например, size: 150, 50 (150 – ширина элемента, 50 – высота элемента);

– pos – абсолютная позиция элемента в окне приложения в пикселах, например, pos: 140, 40 (140 – координата по оси x, 40 – координата по оси y).

2.6.2. Задание виджетам цвета фона

В этом разделе мы узнаем, как изменить цвет фона на примере кнопки. В Kivy существует свойство с именем background_color. Это свойство определяет одно цветовое значение, которое используется для изменения цвета фона элемента.

По умолчанию цвет кнопки серый, если необходимо его изменить, то используется это свойство. Для получения чистого цвета RGB (красный, зеленый, синий) параметры этого свойства должны принимать значение от 0 до 1 (например, background_color:1,0,0,1 – красный цвет, 0,1,0,1 – зеленый цвет, 0,0,1,1 – синий цвет).

В интернете на ряде сайтов можно найти информацию, что эти параметры могут принимать только значение от 0 до 1, и любое другое значение приведет к некорректному поведению программы. Это, скорее всего, имеет отношение к одной из старых версий документации. К настоящему моменту разработчики внесли некоторые изменения в программный код своих функций, и эти величины могут принимать значения, отличные от 0 и 1, что обеспечивает возможность получать весь спектр цветов.

Рассмотрим это на примере изменения цвета кнопок. Создадим файл Button_Color.py и напишем там следующий программный код (листинг 2.45).

Листинг 2.45. Задание цвета кнопкам через свойство background_color (модуль Button_Color.py)

# модуль Button_Color.py

from kivy. app import App

from kivy.lang import Builder

KV = «»»

GridLayout:

…… cols: 3

…… rows: 2

…… Button:

…… …… text: «Красный»

…… …… background_color: 1, 0, 0, 1

…… Button:

…… …… text: «Зеленый»

…… …… background_color: 0, 1, 0, 1

…… Button:

…… …… text: «Синий»

…… …… background_color: 0, 0, 1, 1

…… Button:

…… …… text: «Черный»

…… …… background_color: 0, 0, 0, 1

…… Button:

…… …… text: «Белый»

…… …… color: 0,0,0,1

…… …… background_normal:»»

…… Button:

…… …… text: «Бирюзовый»

…… …… background_color: 102/255, 255/255, 255/255, 1

«»»

class MainApp (App):

…… def build (self):

…… … … return Builder. load_string (KV)

MainApp().run ()

Здесь мы создали таблицу из трех колонок и двух строк, в которую разместили 6 кнопок. Каждой кнопке задали свой цвет.

Примечание.

Обратите внимание, что для задания белого цвета фона используется другое свойство – «background_normal:».

Поскольку на белом фоне не будет видна надпись белого цвета, то для текста, который выводится на этой кнопке, был задан черный цвет (color: 0,0,0,1). Для задания бирюзового цвета использовалось значение параметра «102/255, 255/255, 255/255, 1». Дело в том, что в таблице цветов RGB бирюзовый цвет имеет значение «102, 255, 255». В текущей версии Kivy параметры этого цвета можно задать простым деление этих значений на число 255.

Для всех цветов последнее (четвертое) значение параметра цвета равно 1. Это, по сути, значение альфа маски (слоя прозрачности) для четырехканальных изображений (четыре канала используются в файлах «.png» для хранения изображений). Значение альфа маски всегда находится в пределах 0—100% (или от 0 до 1). При значении 1 будет получен «чистый» цвет (маска прозрачная), 0 – черный цвет (маска не прозрачная), промежуточные значения между 0—1 (полупрозрачная маска) будут давать заданный цвет с разной степенью яркости (затененности). Здесь мы задали значение данного параметра 1. Необходимо следить за очередными версиями Kivy, поскольку в документации может появиться информация об изменениях способов задания цвета.

Результаты работы этой программы представлены на рис. 2.37.


Рис. 2.37. Изменение цвета кнопок с использованием свойства background_color


Итак, мы познакомились с возможностью задавать цвета визуальному виджету с использованием свойства background_color: r, g, b, a (например, background_color: 1, 0, 0, 1).

2.6.3. Обработка событий виджетов

Как и многие другие инструменты для разработки пользовательского интерфейса, Kivy полагается на события. С использованием данного фреймворка можно реализовать отклик на касание клавиш, на касание кнопок мыши или прикосновения к сенсорному экрану. В Kivy задействован концепт часов (Clock), что дает возможность создать отложенный вызов функций через заданное время.

В Kivy реализовано два способа реагирования на события:

– явное связывание визуального элемента с заданной функцией;

– неявное связывание визуального элемента с заданной функцией.

Рассмотрим обе эти возможности. Для явного связывания визуального элемента с заданной функцией создадим новый файл Button_Otklik1.py и внесем в него следующий код (листинг 2.46).

Листинг 2.46. Явное связывание визуального элемента с функцией отклика на действия пользователя (модуль Button_Otklik1.py)

# модуль Button_Otklik1.py

from kivy. app import App

from kivy. uix. button import Button

class MainApp (App):

…… def build (self):

…… … … button = Button (text=«Кнопка»,

…… … … …… … … size_hint= (.5,.5),

…… … … …… … … pos_hint= {’center_x’:.5, ’center_y’:.5})

…… … … button.bind(on_press=self.press_button)

…… … … return button

…… def press_button (self, instance):

…… … … print («Вы нажали на кнопку!»)

MainApp().run ()

Здесь в базовом классе мы реализовали две функции:

– в первой (def build) мы создали кнопку, поместили ее в центре окна приложения и связали событие нажатие кнопки (on_press) с функцией – press_button;

– во второй функции (def press_button) мы прописали действия, которые необходимо выполнить при касании кнопки (в качестве такого действия задан вывод в терминальное окно сообщения ««Вы нажали на кнопку!»).

После запуска данного приложения мы получим следующее окно (рис.2.38).


Рис. 2.38. Окно приложения с кнопкой, выполняющей запрограммированные действия


Теперь каждый раз, когда пользователь будет нажимать кнопку (касаться кнопки), в окне терминала будет появляться сообщение – «Вы нажали на кнопку!» (рис.2.39).


Рис. 2.39. Окно терминала с результатами действия при нажатии на кнопку


В данном примере модуль был создан в коде на языке Python. А сейчас реализуем тот же пример с использованием языка KV. Для этого создадим файл с именем Button_Otklik11.py и напишем в нем следующий код (листинг 2.47).

Листинг 2.47. Явное связывание визуального элемента с функцией отклика на действия пользователя (модуль Button_Otklik11.py)

# модуль Button_Otklik11.py

from kivy. app import App

from kivy.lang import Builder

KV = «»»

Button:

…… text: «Кнопка»

…… size_hint:.5,.5

…… pos_hint: {’center_x’:.5, ’center_y’:.5}

…… on_press: app.press_button (root)

«»»

class MainApp (App):

…… def build (self):

…… …… return Builder. load_string (KV)

…… def press_button (self, instance):

…… …… print («Вы нажали на кнопку!»)

MainApp().run ()

Здесь в строковой переменной KV обрабатывается событие нажатия кнопки (on_press). При возникновении данного события выполняется обращение к функции приложения press_button, которая находится в корневом модуле (root). Результаты работы приложения будут такими же, как представлено на двух рисунках выше.

На языке Kivy достаточно просто организована обработка событий:

«событие: функция обработки события»

Например, у кнопки имеются зарезервированное событие – on_press (касание кнопки). Если обработка этого события реализуется непосредственно в коде на KV, то это делается следующим образом:

Button:

…… on_press: print («Кнопка нажата»)

Если обработка события реализуется в разделе приложении, написанном на Python, то можно использовать следующий код:

# это код на KV

Button:

on_press: app.press_button (args)

# это код на Python

def press_button (self):

print («Вы нажали на кнопку!»)

Для неявного связывания визуального элемента с заданной функцией создадим новый файл Button_Otklik2.py и внесем в него следующий код (листинг 2.48).

Листинг 2.48. Неявное связывание визуального элемента с функцией отклика на действия пользователя (модуль Button_Otklik2.py)

# модуль Button_Otklik2.py

from kivy. app import App

from kivy. uix. button import Button

class Basic_Class1 (App):

…… def build (self):

…… … … button = Button (text=«Кнопка»,

…… … … … … ….. … size_hint= (.5,.5),

…… … … … … ….. … pos_hint= {’center_x’:.5, ’center_y’:.5})

…… return button

…… def press_button (self):

…… … … print («Вы нажали на кнопку!»)

My_App = Basic_Class1 () # приложение на основе базового класса

My_App.run () # запуск приложения

В данном коде создана кнопка button на основе базового класса Button, но эта кнопка не имеет связи с функцией обработки события ее нажатия, хотя сама функция press_button присутствует.

С первого взгляда данный код может показаться странным, так как кнопка button не связана с функций реакции на событие нажатия кнопки. Такую связку можно реализовать на уровне языка KV. Вспомним, что при запуске головного модуля Kivy автоматически ищет файл с таким же названием, что и у базового класса (в данном случае файл – basic_class1.kv), и выполняет запрограммированные там действия. Найдем в своем проекте (или создадим) файл с именем basic_class1.kv и внесем в него следующий программный код (листинг 2.49).

Листинг 2.49. Содержание файла basic_class1.kv (модуль basic_class1.kv)

# файл basic_class1.kv

<Button>:

…… on_press: app.press_button ()

Иными словами мы связь отклика на нажатия кнопки перенесли из основного модуля, в связанный модуль на языке KV. Если теперь запустить программу на выполнение, то мы получим тот же результат, что и в предыдущем программном модуле.

2.7. Дерево виджетов – как основа пользовательского интерфейса

В приложениях на Kivy – пользовательский интерфейс строится на основе дерева виджетов. Принципиальная структура дерева виджетов приведена на рис.2.40.


Рис. 2.40. Структура дерева виджетов


Основой дерева виджетов является «Корневой виджет». Это, по сути, контейнер, в котором находятся дочерние элементы, или виджеты ветки. На приведенном выше рисунке, в корневом виджете – контейнере имеется две ветки («Виджет ветвь 1» и «Виджет ветвь 2»). В свою очередь, каждая из этих веток может иметь свои ответвления. В частности «Виджет ветвь 1», так же является контейнером, в котором находится «Виджет ветвь 1.1». Каждая ветка дерева может иметь «листья». Лист – это конечный элемент в дереве виджетов. Каждый лист – это свойство виджета, которое имеет параметр с заданным значением. Кроме свойства «лист» может содержать и метод, связанный с обработкой события (ссылка на функцию, в которой будет обработано событие, касающееся данного виджета). Структура дерева виджетов может быть сформирована как с использованием языка KV, так и на языке Python.

В приложении может быть только один корневой виджет и любое количество веток, или дочерних виджетов. Виджет представляет собой объект, созданный на базе одного из базовых классов фрейморка Kivy. Базовые классы фрейморка Kivy, на которых можно построить пользовательский объект, можно разделить на две категории:

– классы для создания видимых виджетов (они отображаются в окне приложения);

– классы для создания невидимых виджетов (они указывают положение видимых виджетов в окне приложения).

В литературе можно встретить различное наименование невидимых виджетов: контейнер, макет, виджет позиционирования, виджет Layout.

При построении дерева виджетов на языке KV каждая последующая ветка в программном коде отделяется от предыдущей ветки с помощью отступов. Корневой виджет всегда начинается с первого символа в редакторе программного кода. Каждая последующая ветвь дерева виджетов имеет отступ в 4 символа и начинается с пятого символа в редакторе программного кода. Например:

Корневой виджет:

…… Дочерний виджет 1:

…… …… Дочерний виджет 1.1:

…… Дочерний виджет 2:

…… …… Дочерний виджет 2.1:

…… …… …… Дочерний виджет 2.1.1:

…… …… …… Дочерний виджет 2.1.2:

В редакторе программного кода такой отступ можно создать с использованием клавиши «Tab».

Виджеты в Kivy организованы в виде деревьев. В любом приложении должен быть один корневой виджет, который обычно имеет дочерние виджеты. Дерево виджетов для приложения можно построить и на языке KV, и на языке Python.

На языке Python дерево виджетов можно формировать с помощью следующих методов:

– add_widget (): добавить виджет к родительскому виджету в качестве дочернего;

– remove_widget (): удалить виджет из списка дочерних элементов;

– clear_widgets (): удалить все дочерние элементы из родительского виджета.

Например, если необходимо добавить кнопку в контейнер BoxLayout, то это можно сделать последовательностью следующих команд:

layout = BoxLayout (padding=10) # Создать контейнер

button = Button (text=«Кнопка») # создать кнопку

layout.add_widget (button) # положить кнопку в контейнер

Для демонстрации этой возможности создадим файл с именем K_Treet_1.py и напишем в нем следующий код (листинг 2.50).

Листинг 2.50. Пример создания дерева виждетов на Python (модуль K_Tree_1.py)

# модуль K_Tree_1.py

from kivy. app import App

from kivy.uix.boxlayout import BoxLayout

from kivy. uix. button import Button

from kivy.uix.screenmanager import Screen

class MainApp (App):

…… def build (self):

…… …… scr = Screen () # корневой виджет (экран)

…… …… box = BoxLayout () # контейнер box

…… …… but1 = Button (text=«Кнопка 1») # кнопка 1

…… …… but2 = Button (text=«Кнопка 2») # кнопка 2

…… …… box.add_widget (but1) # положить кнопку 1 в контейнер

…… …… box.add_widget (but2) # положить кнопку 2 в контейнер

…… …… scr.add_widget (box) # положить контейнер в корневой виджет

…… return scr

MainApp().run ()

В этом модуле мы создали корневой виджет scr (экран) на основе базового класса Screen. Затем создали контейнер box на основе базового класса BoxLayout. После этого создали две кнопки but1 и but2 на основе базового класса Button. На следующем этапе эти кнопки положили в контейнер, а сам контейнер поместили в корневой виджет. После запуска данного приложения получим следующий результат (рис.2.41).


Рис. 2.41. Результаты выполнения приложения из модуля K_Treet_1.py


Программный код получился достаточно длинным, поскольку для каждого базового класса приходится делать импорт соответствующего модуля.

Аналогичный код на языке KV будет выглядеть гораздо проще и понятней:

Screen: # создание корневого виджета (экран)

…… BoxLayout: # создание контейнера BoxLayout

…… Button: # добавление в контейнер виджета Button (кнопка)

…… Button: # добавление в контейнер виджета Button (кнопка)

Для демонстрации этого создадим файл с именем K_Treet_2.py и напишем в нем следующий код (листинг 2.51).

Листинг 2.51. Пример создания дерева виждетов на Python (модуль K_Tree_2.py)

# модуль K_Tree_2.py

from kivy. app import App

from kivy.lang import Builder

KV = «»»

Screen: # создание корневого виджета (экран)

……BoxLayout: # создание контейнера BoxLayout

…… …… Button: # добавление в контейнер виджета Button (кнопка)

…… …… …… text: «Кнопка 1»

…… …… Button: # добавление в контейнер виджета Button (кнопка)

…… …… …… text: «Кнопка 2»

«»»

class MainApp (App):

…… def build (self):

…… …… return Builder. load_string (KV)

MainApp().run ()

После запуска приложения мы получим тот же результат, что и на предыдущем рисунке. При этом сам код стал компактней, поскольку нет необходимости явным образом импортировать модули с базовыми классами (они подгружаются автоматически).

При использовании языка Python при создании элемента можно сразу задать и его свойства. Например, в предыдущих примерах это было сделано следующим образом:

but1 = Button (text=«Кнопка 1»)

Аналогичный код на языке KV выглядит иначе:

Button:

…… text: «Кнопка 1»

Примечание.

На языке KV имена виджетов должны начинаться с заглавных букв, а имена свойств – со строчных букв.

Теперь можно более детально познакомиться с виджетами – контейнерами, которые отвечают за размещение видимых элементов интерфейса на экране, и используется для построения дерева виджетов.

The free sample has ended.

Genres and tags

Age restriction:
12+
Release date on Litres:
02 March 2022
Volume:
582 p. 305 illustrations
ISBN:
9785005618719
Download format: