категории | RSS
  

Создание и управление интерфейсом на Android с помощью Python

Добрый день.
Хотел бы предоставить на ваш суд свою первую статью о программировании на Python под Android. Сразу оговорюсь, что я не специалист в этой области, учусь вместе с вами. Как и многие из нас, начинал писать приложения на старой доброй OS Symbian. Однако прогресс не стоит на месте, и на смену старому всегда приходит новое. Вот с этим новым мне и пришлось столкнуться, когда я приобрел HTC Wildfire на платформе Android...
Разобравшись с новым устройством, я решил, что, наконец, пришло время установить полюбившийся многим интерпретатор языка программирования Python.
В Интернете наткнулся на SL4A (Scripting Layer For Android) - оболочку, которая, позволяет создавать и запускать скрипы,
написанные на различных языках
сценариев (Python, Perl, Ruby, Lua, BeanShell, javascript и Tcl) прямо на Android - устройствах. Описывать работу с этой оболочкой я не буду, поскольку ниже есть ссылка на соответствующую статью от "Питон на Android. Начало".
Наверное, ни для кого не секрет, что "родные" приложения для Android пишутся на Java (не путайте с платформой Java2ME). Так вот, сценарии, написанные с помощью SL4A, имеют доступ ко многим API, доступным для нормального Java приложения, но с упрощенным интерфейсом...
Установил, проверил, стало грустно. Потому что, если на Symbian Python был чуть ли не всемогущ, и зачастую приложение, написанное на нем, не уступало аналогам на Си, то на Android, сделать что-то большее, чем общение с пользователем посредством диалоговых окон или запуск скрипра в фоновом режиме, увы, не удастся. С другой стороны мы имеем модуль android, который позволяет программисту создавать все те же диалоговые окна, selection list, вызывать прогресс бар, отправлять/читать сообщения и многое другое. То есть с его помощью мы имеем доступ практически ко всем необходимым для разработки приложения функциям смартфона. Но! Мы не имеем возможности создать более менее приличный интерфейс к нашим приложениям. К счастью, все это заблуждение!
На платформе Android Python-программист имеет возможность создавать интерфейс пользователя двумя способами. Первый - с помощью функции из модуля android webViewShow, которой в качестве аргумента передается строка, путь к html-документу, который и будет интерфейсом приложения. Все события такого приложения будут передоваться в Python-сценарий с помощью кода на Java-script в html-странице интерфейса приложения. Подробнее о webViewShow можно прочитать в статье от пользователя Zaterehniy Питон на Android. Начало. Однако должен сказать, что у этого способа создания интерфейса есть огромный минус - html перестает отвечать на действия пользователя буквально после нескольких обработанных событий. Увы, но это так. К счастью у нас есть второй, на 100% действенный, способ
создания пользовательского
интерфейса — fullScreenUI.
Начиная с версии SL4A_r5, появился новый, как заявили разработчики, пока что
экспериментальный, способ создания пользовательского интерфейса — fullScreenUI. FullScreenUI позволяет создавать интерфейс, используя стандартные виджеты Android (кнопки,
текстовые поля, радиокнопки, и
проч.), а также обрабатывать события от них.
Весь интерфейс нашего приложения, как и в "родной" программе на Java, будет описан в xml-макете, код же самого сценария будет записан в отдельном файле. Android-разработчики используют два определения термина «макет». Первое — тип ресурса, определяющий то, что будет на экране. Макеты хранятся в виде xml-файлов в /res/layout директории приложения. Второе определение: макет - это просто шаблон для экрана пользовательского интерфейса, компановка тех или иных элементов, которые будет видеть пользователь.
В xml-контейнере мы лепим визуальную часть приложения: здесь будет текстовое поле, оно будет черного цвета, внизу будет кнопка с надписью "Сохранить", она будет зеленого цвета и так далее. На самом деле это очень удобно, поскольку мы отделяем интерфейс от кода нашей программы. В этой статье я не буду вдаваться в подробности xml разметки на Android, а всего лишь покажу как управлять этими елементами из сценария на языке Python.
Более подробно об xml разметке на Android вы можете прочитать здесь.
Все примеры, которые я приведу в этой статье, используют droidInterface.py - оболочку для работы с модулем android. Оболочку я пишу для себя, потому что мне так проще, это не конечный результат, и если вы не испытываете затруднений с использованием модуля android, она вам не нужна, перепишите примеры под оригинальный API.
Итак, начнем. Все сценарии у меня лежат в

/sdcard/sl4a/scripts/ExampleUI
. У вас они могут находится где угодно. Создадим папку нашего первого примера. Назовем ее Example. В этой папке создайте папку ресурсов res, в которой будет подпапка layout. Я всегда придерживаюсь данной структуры приложения, чего и вам советую. В итоге у вас должна получится директория
/sdcard/sl4a/scripts/Exampe/res/layout
. В корне проекта будет находится наш Python-сценарий, demo.py, а в папке layout файл макета интерфейса main.xml с нижеследующим содержанием:

main.xml


<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
android:layout_width = "fill_parent"
android:layout_height= "fill_parent"
android:orientation ="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width= "wrap_content"
android:layout_height="wrap_content"
android:text = "Button 1"/>
<Button
android:layout_width= "wrap_content"
android:layout_height="wrap_content"
android:text = "Button 2"/>
<Button
android:layout_width= "wrap_content"
android:layout_height="wrap_content"
android:text = "Button 3"/>
</LinearLayout>


А вот сам Python сценарий:


# demo.py
import sys
import os

import droidInterface

droid = droidInterface.droid
fullway = os.path.dirname(__file__)

droidInterface.set_menu([("Exit", "ic_menu_close_clear_cancel")])

droid.fullShow(open("%s/res/layout/main.xml"%(fullway)).read())

while True:
event = droid.eventWait().result
if event["name"] == "Exit":
sys.exit()
else:
droidInterface.note(str(event))


Вот, что у нас получилось:



Теперь немного о самом коде...

import droidInterface
- оболочка для работы с модулем android.

droid = droidInterface.droid
- переменной droid присваиваем экземпляр класса Android, который определен в модуле droidInterface; через droid мы будем работать со стандартным API.

fullway = os.path.dirname(__file__)
- получаем полный путь к папке с нашим сценарием.

droidInterface.set_menu([("Exit", "ic_menu_close_clear_cancel")])
- вешаем на кнопку "menu" наше меню ;первый аргумент - название пункта, второй - имя используемой иконки; если мы хотим меню из нескольких пунктов, тогда нам нужно передать в функцию set_menu список кортежей:
droidInterface.set_menu([("Имя пункта", "имя иконки"), ("Имя пункта2", " Имя иконки2")])


droid.fullShow(open("%s/res/layout/main.xml"%(fullway)).read())
- думаю здесь понятно, метод fullShow принимает строку с нашим макетом интерфейса;


while True:
event = droid.eventWait().result
- функция droid.eventWait останавливает сценарий и ждет действий от со стороны пользователя; результатом выполнения (переменная event) будет ассоциативный массив с именем события и информацией о нем;


if event["name"] == "Exit":
sys.exit()
- для начала проверяем значение event["name"], если оно равно "key", то была нажата кнопка, код
которой можно узнать из event ["data"]["key"] ; если же оно равно
"click", то было нажатия на один из виджетов, id которого можно узнать из event["data"]["id"] ; посмотрите содержимое появляющегося окошка, проанализируйте...

Теперь давайте попробуем динамически изменить наш интерфейс.

main.xml


<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/background"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello SL4A full
screen UI!"/>
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ok"/>
</LinearLayout>


Сценарий:


# demo.py
import os
import sys

import droidInterface

droid = droidInterface.droid

droidInterface.set_menu([("Exit", "ic_menu_close_clear_cancel")])

droid.fullShow(open("%s/res/layout/layout.xml" %(os.path.dirname(__file__))).read())

while True:
event = droid.eventWait().result
if event["name"] == "Exit":
sys.exit()
elif event["name"] == "click":
if event["data"]["id"] == "button":
# изменяем вид интерфейса
droid.fullSetProperty("editText", "text", "properties edited!")
droid.fullSetProperty("background",
"backgroundColor", "0xff7f0000")


Вот, что у нас получилось:



Теперь если мы нажмем на кнопку "Ok", наш интерфейс динамически поменяет свой облик:



Динамически изменять элементы графического интерфейса и содержание форм мы можем с помощью метода droid.fullSetProperty, который принимает три параметра: id виджета, название свойства, присваиваемое значение.
id виджета. Находится в файле main.xml и задается программистом. Например форме для ввода текста
<EditText>
мы присвоили id -
android:id=
"
@+id/editText
".
Название свойства. Это может быть, например, текст в форме или имя кнопки. Заметьте, что изначально в форме
<EditText> 
мы не указывали свойство "text" (
android:text=
"properties edited")
Присваиваемое значение. Тут, думаю, все понятно. Это может быть новое имя пункта, список Listbox, цвет фона и т.д.
Так, если бы мы захотели динамически изменить и имя кнопки на, скажем, "New Name", то должны были добавить в условие строчку
droid.fullSetProperty("button", 
"text", "NEW NAME")


На этом все. Основные принципы, думаю, понятны. Если кому-то помогла это статья, пишите, выложу еще. И оставляйте комментарии, потому что мы учимся вместе


HeaTTheatR
2013-02-12T16:23:31Z
Здесь находятся
всего 0. За сутки здесь было 0 человек

Комментарии 5

#5   Zaterehniy    

отдельные фреймворки позволяют плотнее поработать с графикой. из под сл4а в этом плане много не сделать. Конечно уровень не тот что на симбе, тут совсем другое.


0 ответить

#5   HeaTTheatR    

dimy44,
Насчет подобия graphics... Пока не копал в эту сторону.


0 ответить

#5   dimy44    

Продолжай конечно, инфа полезная. Насчет возможностей... Ну хз, я полгода назад ковырял, тогда все выглядело убого. Щас может и по-другому бы взглянул.
-------------
Добавлено в 22.26: Кстати вопрос назрел, раз речь про гуй зашел- как сейчас там обстоят дела с работой с изображениями, рисованием примитивов? Есть какое подобие graphics из pys60?


0 ответить

#5   HeaTTheatR    

dimy44, В сети море информации. Вспомни, как начиналось на Симбе, никто толком ничего не знал, с миру по нитке, так и докатились до Андроид. Думаю, никто спорить не станет, что Питон на Андроид, все-таки, это не Питон на Симбе, а гораздо интересней smile Возможности, касательно построения графических изысков, ничуть не хуже. Я думаю продолжить серию статей, сегодня, если успею, выложу пример текстового редактора.


* редактировал(а) HeaTTheatR 23:22 13 фев 2013

0 ответить

#5   dimy44    

как ни крути, но после симбы возможности питона на андроиде мягко говоря не очень. Одно время я тоже копал в этом направлении и не был в восторге. Конечно, низкий уровень вхождения и скорость разработки подкупают. И SL4A развивается, посмотрим что дальше будет.


0 ответить

Напомнить пароль