simakazi 02.03.2011 17:01

PythonПишем первый плазмоид на Python.

В этом посте я постараюсь максимально доступно описать весь процесс создания простого плазмоида на Python.
Я постараюсь показать, что написание своих виджетов - это просто, быстро и полезно!
Для понимания сути происходящего неплохо бы предварительно познать сам Python, поставить KDE ;-), PyKDE, PyQt и поддержку питоновского скриптового движка для плазмы (пакет plasma-scriptengine-python в deb-based дистрибутивах).
Наш первый плазмоид будет выполнять простую функцию: показывать карму пользователя welinux.ru, имя которого было введено в соответствующее поле.

Создание структуры проекта
Во-первых, что же скрывается внутри каждого файла-плазмоида?
На самом деле, любой файл filename.plasmoid является zip-архивом, содержащим внутри себя особую структуру директорий. Начнём с её создания.
Пусть директория нашего проекта будет называться welinux_karmometer. В этой директории надо выполнить команду mkdir -p contents/code. Директория code будет содержать в себе главный скриптовый файл main.py.

В директории contents могут быть представлены следующие поддиректории:
contents/images - содержит изображения, используемые плазмоидом
contents/ui - содержит файлы с разметкой UI (нас не касается, мы пишем на Python)
contents/locale - содержит переводы в установленном формате
contents/config - содержит файлы с настройками в формате KConfigXt

metadata.desktop
Описание плазмоида содержится в файле метаданных metadata.desktop, который находится в корне нашего проекта. Пример такого файла:

Encoding=UTF-8
Name=Welinux karma-meter
Name=Кармометр для Welinux
Comment=Shows user's karma for http://welinux.ru
Comment=Смотри за кармой юзернейма с http://welinux.ru
Icon=/icon.png
Type=Service
ServiceTypes=Plasma/Applet
X-Plasma-API=python
X-Plasma-MainScript=code/main.py
X-KDE-PluginInfo-Author=simakazi
X-KDE-PluginInfo-Email=mail@mail.mail
X-KDE-PluginInfo-Name=welinux_karmometer
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://welinux.ru
X-KDE-PluginInfo-Category=Examples
Остановимся на нём поподробнее.
1. Заголовок файла. Не трогай его, %username%!
2. Значение параметра Encoding менять не стоит, если Вы не старообрядец.
3-4. Параметр Name указывает на название плазмоида, которое будет отображаться в обозревателе плазмоидов. Этот параметр можно перевести на разные языки, указав их в квадратных скобках.
5-6. Значение Comment будет отображено на вкладке About вашего виджета в обозревателе плазмоидов. Этот параметр также можно переводить.
7. Icon указывает на пиктограмму, соответствующую нашему виджету. Показанный в примере путь указывает на файл welinux_karmometer/icon.png. Можно также использовать пиктограммы, поставляющиеся с кедами, например, accessories-calculator.
8-9. Тип описываемого desktop-файла. Говорим, что описываем апплет плазмы.
10. Используемый API. Код плазмоида может быть написан на C++, Python, Ruby и JavaScript. Мы пишем на Python.
11. Путь к главному скриптовому файлу.
12-13. Имя автора и e-mail для связи. E-mail будет подставляться в обозревателе плазмоидов в строку вида "О всех ошибках и багах пишите на %your_email%", учтите это.
14-16. Имя нашего плазмоида в системе, его версия и связанный с ним сайт (например, http://kde-look.org, если планируется там распространять плод трудов своих)
17. Категория, к которой относится наш плазмоид. За полным списком категорий проследуйте сюда.

Более подробное описание структуры пакета плазмы и файла metadata.desktop находится здесь.

main.py
Пришла пора немножечко покодить.
Ниже представлен листинг файла welinux_karmometer/contents/code/main.py:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# -*- coding: utf-8 -*-
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import QHttp
from PyKDE4.plasma import Plasma
from PyKDE4 import plasmascript
import re

class WelinuxKarmometer(plasmascript.Applet):
def __init__(self,parent,args=None):
plasmascript.Applet.__init__(self,parent)

def init(self):
self.setHasConfigurationInterface(False)
self.setAspectRatioMode(Plasma.IgnoreAspectRatio)

self.theme = Plasma.Svg(self)
self.theme.setImagePath("widgets/background")
self.setBackgroundHints(Plasma.Applet.DefaultBackground)

self.layout = QGraphicsLinearLayout(Qt.Vertical, self.applet)
self.lineUsername=Plasma.LineEdit(self.applet)
self.browserResult=Plasma.TextBrowser(self.applet)
self.layout.addItem(self.lineUsername)
self.layout.addItem(self.browserResult)
self.applet.setLayout(self.layout)

self.resize(200,100)

self.http=QHttp(self)

self.lineUsername.returnPressed.connect(self.lookUp)
self.connect(self.http,SIGNAL("done(bool)"),self.doneHttp)

def lookUp(self):
self.browserResult.setText("...")
self.http.setHost("welinux.ru")
self.http.get("/user/"+self.lineUsername.text())

def doneHttp(self,error):
if error:
self.browserResult.setText('<font color="#ff0000"><b>'+self.http.errorString()+'</b></font>')
else:
result=re.findall("<span class='r(.)'>(.*?)</span>",unicode(QString.fromUtf8(self.http.readAll().data())))
if result:
self.browserResult.setText('<font color="'+<'#ff0000','#00ff00'><result><0><0>=='p'>+'">'+result<0><1>+'</font>')
else:
self.browserResult.setText("<i>User not found.</i>")
def CreateApplet(parent):
return WelinuxKarmometer(parent)</result>


Разберём этот код подробно.
Во-первых, поддержка плазмы в Python реализована через расширение PyQt и PyKDE, поэтому оба модуля мы включаем в наш скрипт. PyQt4.QtNetwork используется для работы с протоколом http, на работу с плазмой этот модуль не влияет.
За import'ами следует описание нашего класса. Чтобы создать класс, описывающий поведение апплета плазмы, необходимо унаследовать его от plasmascript.Applet и не забыть проинициализировать суперкласс в методе __init__. Всю инициализацию своего виджета следует вынести из __init__ в init, который будет вызван классом Applet после своей инициализации.

В init мы сообщаем, что наш апплет не будет иметь окна настройки, а его размер можно изменять свободно. Далее в качестве фона апплета устанавливается фон, определённый в текущей теме плазмы.

Создание разметки интерфейса начинается с 21й строки.
Особенность плазмоидов в том, что они используют не стандартные виджеты Qt, а свой особый набор виджетов, которые отрисовываются отдельным движком. Полный их список представлен здесь. Но знакомство с Qt упростит понимание происходящего далее.
Сперва мы создадим простой layout (QGraphicsLinearLayout), расположенный вертикально (Qt.Vertical). Плазма использует свои особые классы для разметки из фреймворка Qt Graphics View.
Плазмоид будет состоять из двух виджетов - строки ввода и текстового окна. В строке ввода пользователь будет указывать имя пользователя, а в текстовом окне (после нажатия пользователем Enter'а) будет выводиться карма.
Так что, мы создаём строку ввода Plasma.LineEdit, текстовый браузер Plasma.TextBrowser, и добавляем их в наш layout.
Сам layout применяем ко всему апплету. Если необходима более сложная разметка, то можно добавлять layout'ы друг в друга, и/или использовать QGraphicsGridLayout.
Затем мы устанавливаем размер всего апплета так, чтобы по высоте влезла и строка ввода, и осталось место для вывода кармы.
Далее создаём объект QHttp, который будет использоваться для общения с сайтом.

Пора прикручивать к созданному интерфейсу логику.
Как видно из строк 32-33, соединение сигналов со слотами можно выполнять двумя способами. Оба работоспособны, но второй считается более pythonic.
Итак, при нажатии Enter'а во время ввода в строку lineUsername произойдёт вызов метода lookUp, а при завершении http-запроса, вызовется doneHttp.
Рассмотрим их по порядку.
В lookUp мы просто берём текущее значение из строки ввода и подставляем его в url, далее вызывается метод get класса QHttp, который выполняет асинхронный запрос.
По окончанию запроса будет произведён вызов метода doneHttp, который при наличии ошибки выведет её в текстовый браузер, а при её отсутствии произведёт поиск по результату запроса с помощью простого регулярного выражения.
Важно помнить, что в плазмоидах не следует выполнять тяжёлую обработку больших объёмов данных, делать синхронные запросы к удалённым серверам и т.п., так как подобные безобразия вызывают подвисания плазмы.

Вот и всё. Остаётся только определить метод создания нашего апплета, который будет вызываться плазмой.

Упаковка, установка, отладка
Пришла пора проверить, что же у нас получилось. В директории welinux_karmometer выполните:
zip -r welinux_karmometer.plasmoid *
plasmapkg -i welinux_karmometer.plasmoid
Первая команда создаст zip-архив с текущим каталогом, а вторая установит плазмоид в систему. Если в дальнейшем потребуется заменить уже установленный плазмоид новой версией, запустите plasmapkg с ключом -u.
Для отладочного просмотра плазмоида можно воспользоваться утилитой plasmoidviewer, которая выведет в консоль все возможные ошибки.

Вот и всё. Теперь Вы можете добавить этот плазмоид себе на рабочий стол и гордиться тем, что создали его сами.

P.S. Данная статья является вводной и не покрывает такие "глубокие" темы, как работа с DataEngine, Extender'ами, окном настроек и пр.


Тэги: plasma python
+ 19 -
Похожие Поделиться

kstep 02.03.2011 17:57 #
Спасибо огромное за статью! Плюсую почти не глядя.

Только одна просьба: отбивай логические блоки в коде пустыми строками чтоб было понятнее. Потому что ты вот пишешь: ...со строки 19... ...видно из строк 27-28... Найти можно, но из-за того, что все строчки монолитно сливаются в один блок и глазу не за что ухватиться, на поиск требуется время.

Если бы эти логические блоки отделялись друг от друга пустыми строками было бы гораздо удобнее понимать код.
simakazi 02.03.2011 20:02 #
Спасибо за замечание! Постарался разбить код на логические блоки.
Volant 02.03.2011 20:12 #
Плюсанул за интересный пост.

Но питон пока не изучил, КДЕ не пользуюсь (Fluxbox) - отложу до лучших времен.
Nikisch 03.03.2011 19:46 #
Ничего из раздела main.py не понял ))
Мне еще долго до написания таких вроде бы примитивов как плазмоиды. Че плазмоиды на баше не пишутся? Из этих питон самый простой язык?
Ну хоть понял, что эти зеленые циферки вверху - карма. Правда, че они дробные...
simakazi 03.03.2011 20:31 #
Самый низкий порог вхождения, пожалуй, у Python и JavaScript, но в JavaScript функциональные возможности плазмы поддерживаются не полностью (в KDE 4.4, как в 4.6 - не знаю). Про Ruby ничего не скажу, использовал его давно и мельком.
Для написания плазмоидов очень полезно знать Qt.
knicefire 29.03.2011 23:17 #
Cпасибо за пост, но у меня почему-то вываливается ошибка при импорте plasmascript :(
Дистрибутив Arch. Использовал для проверки python2 и python3.


>>> from PyKDE4.plasma import plasmascript
Traceback (most recent call last):
File "", line 1, in
ImportError: cannot import name plasmascript
>>>

simakazi 04.04.2011 22:19 #
plasma-scriptengine-python установлен в системе?
knicefire 05.04.2011 08:56 #
его в aur искать? в основных репозиториях нету. Поставил то что выдало по pacman -Ss python | egrep "kde|plasma" (extra/kdebindings-python 4.6.1-1 <установлен>)
simakazi 05.04.2011 22:19 #
К сожалению, с Arch я не работал, не знаю. В Сусе питоновский скриптовый движок плазмы предоставляется пакетами python-kdebase4 и python-devel.
simakazi 05.04.2011 22:20 #
Upd. Для Арча вот здесь советуют kdebindings-python поставить. Отпишитесь, если поможет.
knicefire 05.04.2011 22:29 #
так в моем ответе выше написано что данный пакет стоит
knicefire 05.04.2011 23:15 #
только что опять проверил - уже plasmascript импортируется без ошибки хотя ничего дополнительно не ставил с того раза - только обновлялся пару раз.
doraneko 30.03.2011 00:00 #
Мало кто знает, но у welinux есть api :D
http://welinux.ru/ajax/r_get?user=USERNAME отдаст json, где есть и рейтинг =)
simakazi 04.04.2011 22:22 #
Да, не знал, так намного красивее получилось бы, но исправлять уже как-то лень: получение значения рейтинга - это всё же не центральная часть поста :-).