Журнал LinuxFormat - перейти на главную

LXF108:KDE4

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Новая: {{Цикл/KDE4}} == KDE 4 под микроскопом == : ''ЧАСТЬ 1 Считаете, что для KDE 4 мало приложений? В ваших силах исправи...)
 
 
Строка 3: Строка 3:
 
: ''ЧАСТЬ 1 Считаете, что для KDE 4 мало приложений? В ваших силах исправить ситуацию – благодаря новой серии учебников от '''Андрея Боровского'''!''
 
: ''ЧАСТЬ 1 Считаете, что для KDE 4 мало приложений? В ваших силах исправить ситуацию – благодаря новой серии учебников от '''Андрея Боровского'''!''
  
Два года назад LXF публиковал цикл статей о программиро-
+
Два года назад LXF публиковал цикл статей о программировании для KDE 3 ([[LXF81:Qt/KDE|LXF81]]–[[LXF85:Qt/KDE|85]]). Тогда это был зрелый рабочий стол, который готовился уступить место KDE 4, и писать
вании для KDE 3 (LXF81–85). Тогда это был зрелый рабо-
+
чий стол, который готовился уступить место KDE 4, и писать
+
 
о нем было легко, не не слишком интересно. Легко – поскольку KDE
 
о нем было легко, не не слишком интересно. Легко – поскольку KDE
 
3 на тот момент был хорошо (даже очень хорошо) документирован,
 
3 на тот момент был хорошо (даже очень хорошо) документирован,
Строка 13: Строка 11:
 
удастся отразить живые моменты рождения новых технологий.
 
удастся отразить живые моменты рождения новых технологий.
  
С KDE 4 все обстоит иначе. Его первый стабильный релиз поя-
+
С KDE 4 все обстоит иначе. Его первый стабильный релиз появился в начале этого года, и сейчас KDE 4 активно развивается.
вился в начале этого года, и сейчас KDE 4 активно развивается.
+
Далеко не все идеи разработчиков получили окончательное воплощение; по-видимому, и сам список технологий, используемых в
Далеко не все идеи разработчиков получили окончательное вопло-
+
щение; по-видимому, и сам список технологий, используемых в
+
 
KDE 4, будет со временем меняться – я, например, не уверен, что
 
KDE 4, будет со временем меняться – я, например, не уверен, что
система Decibel, о которой будет сказано ниже, войдет в последую-
+
система Decibel, о которой будет сказано ниже, войдет в последующие релизы. Что же касается документации и примеров, то стоит
щие релизы. Что же касается документации и примеров, то стоит
+
 
ли говорить, что для многих частей KDE 4 и то, и другое существует
 
ли говорить, что для многих частей KDE 4 и то, и другое существует
 
либо в зачаточной стадии, либо вовсе отсутствует. Именно поэтому
 
либо в зачаточной стадии, либо вовсе отсутствует. Именно поэтому
писать о KDE 4 гораздо интереснее. У нас есть возможность про-
+
писать о KDE 4 гораздо интереснее. У нас есть возможность проследить глазами программиста рождение нового рабочего стола, с
следить глазами программиста рождение нового рабочего стола, с
+
 
которым пользователи Linux будут жить несколько ближайших лет.
 
которым пользователи Linux будут жить несколько ближайших лет.
 
Как и в случае с Qt 4, мы будем предполагать, что вы уже знакомы
 
Как и в случае с Qt 4, мы будем предполагать, что вы уже знакомы
Строка 34: Строка 28:
 
На внешних красотах KDE 4, усиленных мощью 3D-ускорителей, мы
 
На внешних красотах KDE 4, усиленных мощью 3D-ускорителей, мы
 
останавливаться не будем, а скорее поднимем капот (или снимем
 
останавливаться не будем, а скорее поднимем капот (или снимем
кожух?) и посмотрим, что же находится внутри. Один из важней-
+
кожух?) и посмотрим, что же находится внутри. Один из важнейших элементов KDE, который сразу бросается в глаза (в нескольких
ших элементов KDE, который сразу бросается в глаза (в нескольких
+
 
смыслах слова) – это Plasma. С точки зрения программиста, она –
 
смыслах слова) – это Plasma. С точки зрения программиста, она –
развитие Qt Graphics View Framework (LXF105). Система Corona рас-
+
развитие Qt Graphics View Framework ([[LXF105:Qt4|LXF105]]). Система Corona расширяет возможности QGraphicsScene, добавляя концепцию апплетов. В результате с элементами графической сцены (т.е. рабочего
ширяет возможности QGraphicsScene, добавляя концепцию аппле-
+
стола) можно связывать мини-приложения. Изначально разработчики Plasma ориентировались на Qt 4.2, в которой, напомню, еще не
тов. В результате с элементами графической сцены (т.е. рабочего
+
стола) можно связывать мини-приложения. Изначально разработ-
+
чики Plasma ориентировались на Qt 4.2, в которой, напомню, еще не
+
 
было встраиваемых виджетов; в результате пришлось придумывать
 
было встраиваемых виджетов; в результате пришлось придумывать
 
аналогичный механизм для внедрения пиктограмм и кнопок. Теперь,
 
аналогичный механизм для внедрения пиктограмм и кнопок. Теперь,
Строка 48: Строка 38:
 
версиях Plasma.
 
версиях Plasma.
  
Минуя другие состояния вещества, перейдем от Plasma к тех-
+
Минуя другие состояния вещества, перейдем от Plasma к технологии Solid. Это – кросс-платформенная подсистема, предназначенная для работы с устройствами. Правда, Solid не позволяет
нологии Solid. Это – кросс-платформенная подсистема, предна-
+
значенная для работы с устройствами. Правда, Solid не позволяет
+
 
KDE-приложениям управлять ими, но предоставляет достаточно
 
KDE-приложениям управлять ими, но предоставляет достаточно
информации, чтобы программа могла подобрать нужные админи-
+
информации, чтобы программа могла подобрать нужные административные средства самостоятельно.
стративные средства самостоятельно.
+
  
 
Еще одна интересная и пока что довольно загадочная новинка
 
Еще одна интересная и пока что довольно загадочная новинка
KDE 4 – Phonon. Это переносимая мультимедиа-подсистема, постав-
+
KDE 4 – Phonon. Это переносимая мультимедиа-подсистема, поставляемая с Qt начиная с версии 4.4. API Phonon состоит из классов
ляемая с Qt начиная с версии 4.4. API Phonon состоит из классов
+
высокого уровня, которые унифицируют доступ к различным библиотекам, связанным с мультимедиа. Судя по документации (которая
высокого уровня, которые унифицируют доступ к различным библи-
+
отекам, связанным с мультимедиа. Судя по документации (которая
+
 
на момент написания статьи была еще не завершена), важную роль
 
на момент написания статьи была еще не завершена), важную роль
в Phonon играют концепция прозрачного доступа к мультимедиа-
+
в Phonon играют концепция прозрачного доступа к мультимедиа-ресурсам, независимо от того, где они расположены, и унаследованная от Qt система «модель-контроллер-вид».
ресурсам, независимо от того, где они расположены, и унаследо-
+
ванная от Qt система «модель-контроллер-вид».
+
  
Технология под названием Decibel должна упростить жизнь раз-
+
Технология под названием Decibel должна упростить жизнь разработчикам IP-телефонов, видеофонов, чатов и т.п. Она написана
работчикам IP-телефонов, видеофонов, чатов и т.п. Она написана
+
 
с использованием чистого Qt 4 (т.е. не зависит от KDE), включает
 
с использованием чистого Qt 4 (т.е. не зависит от KDE), включает
 
в себя реализацию Telepathy и многих других полезных вещей, но,
 
в себя реализацию Telepathy и многих других полезных вещей, но,
судя по сайту проекта (decibel.kde.org), работа над ним застопори-
+
судя по сайту проекта (http://decibel.kde.org), работа над ним застопорилась примерно год назад. Текущая версия – 0.5, что будет дальше – посмотрим.
лась примерно год назад. Текущая версия – 0.5, что будет даль-
+
ше – посмотрим.
+
  
 
=== Инструменты разработчика ===
 
=== Инструменты разработчика ===
Строка 78: Строка 58:
 
4 доступен по умолчанию, но и тут могут возникнуть неожиданные
 
4 доступен по умолчанию, но и тут могут возникнуть неожиданные
 
проблемы. Например, в «живом» OpenSUSE 11.0 KDE Four Live с
 
проблемы. Например, в «живом» OpenSUSE 11.0 KDE Four Live с
KDE 4.1 Beta2 обнаружилась одна серьезная и надоедливая ошиб-
+
KDE 4.1 Beta2 обнаружилась одна серьезная и надоедливая ошибка – любое приложение KDE 4, выводящее стандартное диалоговое
ка – любое приложение KDE 4, выводящее стандартное диалоговое
+
 
окно, вызывает фатальный сбой в KNotify (о чем тут же сообщает
 
окно, вызывает фатальный сбой в KNotify (о чем тут же сообщает
 
еще один диалог). Поэтому нам придется довольствоваться KDE
 
еще один диалог). Поэтому нам придется довольствоваться KDE
4.04, входящим в состав OpenSUSE 11.0. Помимо собственно гра-
+
4.04, входящим в состав OpenSUSE 11.0. Помимо собственно графической среды, нам, разумеется, понадобятся пакеты разработчика Qt 4.x и KDE 4.x.
фической среды, нам, разумеется, понадобятся пакеты разработчи-
+
ка Qt 4.x и KDE 4.x.
+
  
 
На момент написания этой статьи стабильного KDevelop 4 еще не
 
На момент написания этой статьи стабильного KDevelop 4 еще не
 
существовало, а нестабильный работал только с тестовой версией
 
существовало, а нестабильный работал только с тестовой версией
 
KDE 4.1, от использования которой мы с вами отказались. В Сети
 
KDE 4.1, от использования которой мы с вами отказались. В Сети
можно найти трюки, с помощью которых можно создавать прило-
+
можно найти трюки, с помощью которых можно создавать приложения KDE 4 в KDevelop 3.x, но мы на них останавливаться не будем:
жения KDE 4 в KDevelop 3.x, но мы на них останавливаться не будем:
+
 
думаю, что KDevelop 4 уже скоро обретет стабильность, и данные
 
думаю, что KDevelop 4 уже скоро обретет стабильность, и данные
советы морально устареют. Лучше потратим сэкономленную жур-
+
советы морально устареют. Лучше потратим сэкономленную журнальную площадь на KDevelop 4, когда он выйдет. Пока же будем
нальную площадь на KDevelop 4, когда он выйдет. Пока же будем
+
 
применять инструменты низкого уровня: это позволит нам глубже
 
применять инструменты низкого уровня: это позволит нам глубже
проникнуть в суть вещей в KDE 4. Не считая стандартных инструмен-
+
проникнуть в суть вещей в KDE 4. Не считая стандартных инструментов разработчика, нам понадобятся две консольные утилиты: cmake
тов разработчика, нам понадобятся две консольные утилиты: cmake
+
 
и kapptemplate – мастер, с вызова которого и начинается процесс
 
и kapptemplate – мастер, с вызова которого и начинается процесс
разработки. Kapptemplate создает заготовки для простого прило-
+
разработки. Kapptemplate создает заготовки для простого приложения KDE, приложения KDE со сложным главным окном или KPart.
жения KDE, приложения KDE со сложным главным окном или KPart.
+
  
 
Далее утилита просит указать имя и расположение нового проекта.
 
Далее утилита просит указать имя и расположение нового проекта.
 
Программа также захочет «познакомиться» – узнать ваши имя и
 
Программа также захочет «познакомиться» – узнать ваши имя и
e-mail. В этом смысле kapptemplate отличается крайней навязчиво-
+
e-mail. В этом смысле kapptemplate отличается крайней навязчивостью и задает личные вопросы при каждом запуске.
стью и задает личные вопросы при каждом запуске.
+
  
Директория, в которой kapptemplate сохраняет файлы заготов-
+
Директория, в которой kapptemplate сохраняет файлы заготовки программы, содержит много интересного (об этом – чуть позже), но в ней отсутствуют Make-файл и сценарий configure, то есть
ки программы, содержит много интересного (об этом – чуть поз-
+
те скрипты, которые мы привыкли использовать для сборки программ KDE 3. Здесь нам на помощь приходит CMake. Этот кросс-платформенный независимый инструмент от компании Kitware
же), но в ней отсутствуют Make-файл и сценарий configure, то есть
+
те скрипты, которые мы привыкли использовать для сборки про-
+
грамм KDE 3. Здесь нам на помощь приходит CMake. Этот кросс-
+
платформенный независимый инструмент от компании Kitware
+
 
стал частью инструментария KDE 4 совсем недавно. Утилита cmake
 
стал частью инструментария KDE 4 совсем недавно. Утилита cmake
 
выполняет для проектов KDE (и не только KDE) ту же работу, что
 
выполняет для проектов KDE (и не только KDE) ту же работу, что
Строка 118: Строка 86:
 
таким именем в вашей системе относится к Qt 4, а не 3.x. Для этого
 
таким именем в вашей системе относится к Qt 4, а не 3.x. Для этого
 
наберите в окне консоли:
 
наберите в окне консоли:
 +
[[Изображение:LXF108 75 1.png|thumb|300px|Рис. 1. Минималистичное приложение KDE 4.]]
 
  qmake --version
 
  qmake --version
 
Если qmake «не тот», ситуацию следует исправить с помощью
 
Если qmake «не тот», ситуацию следует исправить с помощью
переменной PATH. В самом простом случае (который мы и рассма-
+
переменной PATH. В самом простом случае (который мы и рассматриваем) для генерации Make-файлов для проекта KDE 4 достаточно
триваем) для генерации Make-файлов для проекта KDE 4 достаточно
+
 
скомандовать
 
скомандовать
 
  cmake <project_path>
 
  cmake <project_path>
где project_path – это путь к проекту. Имейте в виду, что cmake соз-
+
где project_path – это путь к проекту. Имейте в виду, что cmake создает выходные файлы, в том числе и Makefile, не в project_path, а
дает выходные файлы, в том числе и Makefile, не в project_path, а
+
 
в той директории, откуда он был вызван. Теперь, наконец, можно
 
в той директории, откуда он был вызван. Теперь, наконец, можно
 
скомандовать
 
скомандовать
Строка 132: Строка 99:
 
же это за зверь такой, сурово указывающий на несвежесть файлов
 
же это за зверь такой, сурово указывающий на несвежесть файлов
 
проекта?
 
проекта?
 +
{{Врезка|center|
 +
|Заголовок=Проект CMake: что внутри?
 +
|Содержание=Если даже раньше вы никогда не работали с CMake, то после
 +
использования данной утилиты должны почувствовать, насколько она удобна. Создать Make-файлы для стандартного проекта
 +
с помощью CMake просто, но вы наверняка хотите знать, как
 +
можно влиять на этот процесс – например, добавить ссылки
 +
на разделяемые библиотеки? В qmake для этого потребовалось
 +
бы отредактировать файл *.pro, а его аналогом в CMake служит CMakeLists.txt. Синтаксис CMakeLists.txt довольно сложен,
 +
поэтому мы рассмотрим только самые важные элементы. Каждая
 +
строка файла содержит команду и ее аргументы, перечисляемые
 +
в круглых скобках. Так, команда project() указывает имя проекта.
 +
Здесь можно также задать язык программирования: С, CXX, Java.
 +
Команда find_package() находит и загружает данные внешнего
 +
пакета. Например,
 +
find_package(KDE4 REQUIRED)
 +
указывает, что требуется загрузить пакет KDE4. Опция REQUIRED
 +
уточняет, что без него сборка проекта невозможна (логично, не
 +
правда ли?). После загрузки пакета KDE4 файлу настройки CMake
 +
становятся доступны определенные в нем переменные и команды. Например, команда Include_directories() использует переменные KDE4_INCLUDES и QT_INCLUDES. Команда kde4_add_ui_files() не относится к числу встроенных в CMake – она также
 +
добавляется пакетом KDE4.
 +
 +
Команда target_link_libraries() (на этот раз – стандартная)
 +
сообщает, какие библиотеки следует подключить к данной цели
 +
сборки (она задается первым аргументом). Команда получает имена библиотек из переменной KDE4_KDEUI_LIBS, которая
 +
определена в пакете KDE4.
 +
 +
С помощью файла CMakeLists.txt настоящие мастера могут
 +
творить чудеса, однако если премудрости его синтаксиса вас
 +
пугают, можете утешиться тем, что вам вовсе не обязательно
 +
знать их все. Если вы используете мастер генерации проектов
 +
KDE 4, то по большей части настройка файла CMakeLists.txt будет
 +
сводиться к незначительному редактированию уже имеющейся
 +
|Ширина=}}
  
 
=== Через увеличительное стекло ===
 
=== Через увеличительное стекло ===
Если ваша программа называется kapp4, то объявление класса глав-
+
Если ваша программа называется kapp4, то объявление класса главного окна содержится в файле kapp4.h (а его методы – в kapp4.
ного окна содержится в файле kapp4.h (а его методы – в kapp4.
+
 
cpp). Класс, реализующий центральный элемент главного окна –
 
cpp). Класс, реализующий центральный элемент главного окна –
KApp4View – располагается в файлах kapp4view.h/kapp4view.cpp и насле-
+
KApp4View – располагается в файлах kapp4view.h/kapp4view.cpp и наследует от Ui::kapp4view_base, объявление которого (файл ui_ kapp4view_base.h) генерируется автоматически на основе описания интерфейса
дует от Ui::kapp4view_base, объявление которого (файл ui_ kapp4view_
+
base.h) генерируется автоматически на основе описания интерфейса
+
 
программы, содержащегося в kapp4view_base.ui. В этой структуре
 
программы, содержащегося в kapp4view_base.ui. В этой структуре
нельзя не заметить влияния Qt 4.x, и (как вы, наверное, уже дога-
+
нельзя не заметить влияния Qt 4.x, и (как вы, наверное, уже догадались) класс kapp4view_base.ui не является потомком QWidget, но
дались) класс kapp4view_base.ui не является потомком QWidget, но
+
содержит инструкции, позволяющие настроить таковой ([[LXF104:Qt4|LXF104]]).
содержит инструкции, позволяющие настроить таковой (LXF104).
+
 
Помимо kapp4view_base.ui, в нашем проекте есть еще один ui-файл –
 
Помимо kapp4view_base.ui, в нашем проекте есть еще один ui-файл –
 
prefs_base.ui, который содержит описание интерфейса окна настроек.
 
prefs_base.ui, который содержит описание интерфейса окна настроек.
 
Забегая вперед, отмечу, что в KDE 4 вы «бесплатно» получаете мощную
 
Забегая вперед, отмечу, что в KDE 4 вы «бесплатно» получаете мощную
 
систему конфигурации приложения пользователем (правда, все равно
 
систему конфигурации приложения пользователем (правда, все равно
уступающую таковой в программе-часах из LXF106).
+
уступающую таковой в программе-часах из [[LXF106:Qt4|LXF106]]).
  
 
Вы, наверное, уже озадачились вопросом: как редактировать
 
Вы, наверное, уже озадачились вопросом: как редактировать
Строка 155: Строка 151:
 
Designer 4.x – он поддерживает и виджеты KDE 4. Файлы settings.h
 
Designer 4.x – он поддерживает и виджеты KDE 4. Файлы settings.h
 
и settings.cpp содержат, соответственно, объявление и определение
 
и settings.cpp содержат, соответственно, объявление и определение
класса Settings. Он наследует от KConfigSkeleton и является осно-
+
класса Settings. Он наследует от KConfigSkeleton и является основой движка настройки нашего приложения. Наконец, файл main.cpp,
вой движка настройки нашего приложения. Наконец, файл main.cpp,
+
 
как нетрудно догадаться, предоставляет функцию main() нашей
 
как нетрудно догадаться, предоставляет функцию main() нашей
 
программы.
 
программы.
Строка 200: Строка 195:
 
Класс главного окна является потомком KXmlGuiWindow,
 
Класс главного окна является потомком KXmlGuiWindow,
 
который происходит от класса KMainWindow, наследующего от
 
который происходит от класса KMainWindow, наследующего от
QMainWindow, наряду с KXmlGuiBuilder и KXmlGuiClient. Ниже при-
+
QMainWindow, наряду с KXmlGuiBuilder и KXmlGuiClient. Ниже приводится листинг конструктора класса главного окна
водится листинг конструктора класса главного окна
+
 
<source lang="cpp-qt">KApp4::KApp4()
 
<source lang="cpp-qt">KApp4::KApp4()
 
: KXmlGuiWindow(), m_view(new KApp4View(this)), m_printer(0) {
 
: KXmlGuiWindow(), m_view(new KApp4View(this)), m_printer(0) {
Строка 219: Строка 213:
 
setupGUI();
 
setupGUI();
 
}</source>
 
}</source>
Я специально не стал убирать из листинга комментарии, добав-
+
Я специально не стал убирать из листинга комментарии, добавленные в него программой-генератором, чтобы показать, что
ленные в него программой-генератором, чтобы показать, что
+
 
файлы-заготовки, созданные kapptemplate, не только освобождают нас от рутинной работы, но и сообщают полезную для новичков
 
файлы-заготовки, созданные kapptemplate, не только освобождают нас от рутинной работы, но и сообщают полезную для новичков
информацию о том, что делают вызываемые функции. Для настрой-
+
информацию о том, что делают вызываемые функции. Для настройки внешнего вида главного окна, как и в KDE 3, используется система KXMLGUI. Напомню, что главное окно хранит данные о меню,
ки внешнего вида главного окна, как и в KDE 3, используется систе-
+
ма KXMLGUI. Напомню, что главное окно хранит данные о меню,
+
 
панелях инструментов и командах в файлах *ui.rc, имеющих формат
 
панелях инструментов и командах в файлах *ui.rc, имеющих формат
 
XML. Для нашего приложения тоже был создан такой – это kapp4ui.
 
XML. Для нашего приложения тоже был создан такой – это kapp4ui.
Строка 230: Строка 221:
 
Тем не менее, при каждом запуске программы на консоль будет
 
Тем не менее, при каждом запуске программы на консоль будет
 
выводиться сообщение о том, что файл kapp4ui.rc не найден (это не
 
выводиться сообщение о том, что файл kapp4ui.rc не найден (это не
приводит к завершению программы, поскольку, не найдя свой соб-
+
приводит к завершению программы, поскольку, не найдя свой собственный rc-файл, приложение берет стандартный из KDE 4). Наша
ственный rc-файл, приложение берет стандартный из KDE 4). Наша
+
 
программа не может найти файл kapp4ui.rc потому, что ищет его не
 
программа не может найти файл kapp4ui.rc потому, что ищет его не
там, где он лежит. Глобально установленные приложения, доступ-
+
там, где он лежит. Глобально установленные приложения, доступные всем пользователям, хранят свои файлы *ui.rc в общедоступной директории (например, /usr/share/kde4/apps/имя_приложения).
ные всем пользователям, хранят свои файлы *ui.rc в общедоступ-
+
Для сохранения ваших персональных настроек следует воспользоваться каталогом ~/.kde4/share/apps/имя_приложения.
ной директории (например, /usr/share/kde4/apps/имя_приложения).
+
Для сохранения ваших персональных настроек следует воспользо-
+
ваться каталогом ~/.kde4/share/apps/имя_приложения.
+
  
 
=== Система настройки ===
 
=== Система настройки ===
 +
[[Изображение:LXF108 76 1.png|thumb|300px|Рис. 2. Окно настройки программы KApp4.]]
 +
[[Изображение:LXF108 76 2.png|thumb|300px|Рис. 3. Смена оформления KApp4.]]
 
Выше я уже упоминал о том, что стандартный проект приложения
 
Выше я уже упоминал о том, что стандартный проект приложения
KDE 4 по умолчанию снабжается системой настройки. Ее можно раз-
+
KDE 4 по умолчанию снабжается системой настройки. Ее можно разделить на две части: настройка панелей инструментов, сочетаний
делить на две части: настройка панелей инструментов, сочетаний
+
 
горячих клавиш – с одной стороны, и конфигурация специфических
 
горячих клавиш – с одной стороны, и конфигурация специфических
 
параметров работы приложения – с другой. Особенность настройки
 
параметров работы приложения – с другой. Особенность настройки
первого типа заключается в том, что, по существу, она одинако-
+
первого типа заключается в том, что, по существу, она одинакова для всех приложений KDE и может быть легко формализована.
ва для всех приложений KDE и может быть легко формализована.
+
 
Однако разработчики KDE на этом не успокоились и сделали все
 
Однако разработчики KDE на этом не успокоились и сделали все
возможное, чтобы охватить и процесс создания средств специфи-
+
возможное, чтобы охватить и процесс создания средств специфической настройки приложений. Окно специальных настроек (рис. 2)
ческой настройки приложений. Окно специальных настроек (рис. 2)
+
 
открывается по команде Configure KApp4... меню Settings.
 
открывается по команде Configure KApp4... меню Settings.
  
 
Как мы видим, здесь можно настроить цвет шрифта и фона
 
Как мы видим, здесь можно настроить цвет шрифта и фона
 
чей областью, ведь он ничего не делает!) и возраст проекта в днях. В
 
чей областью, ведь он ничего не делает!) и возраст проекта в днях. В
результате внешний вид программы может довольно сильно изме-
+
результате внешний вид программы может довольно сильно измениться (рис. 3).
ниться (рис. 3).
+
  
 
Глобальные установки хранятся в директории /usr/share/kde4/config, а локальные – в ~/.kde4/share/config. После нескольких
 
Глобальные установки хранятся в директории /usr/share/kde4/config, а локальные – в ~/.kde4/share/config. После нескольких
 
запусков программы KApp4 я нашел в ней два файла: KApp4rc, где
 
запусков программы KApp4 я нашел в ней два файла: KApp4rc, где
хранятся параметры рабочей области, и kapp4rc, содержащий дан-
+
хранятся параметры рабочей области, и kapp4rc, содержащий данные о геометрии главного окна и видимости его элементов. Следует
ные о геометрии главного окна и видимости его элементов. Следует
+
отметить, что многие программы KDE 4 хранят свои параметры конфигурации сразу в нескольких файлах.
отметить, что многие программы KDE 4 хранят свои параметры кон-
+
фигурации сразу в нескольких файлах.
+
  
 
Для управления настройками создается глобальный объект
 
Для управления настройками создается глобальный объект
класса Settings. Получить указатель на него можно с помощью ста-
+
класса Settings. Получить указатель на него можно с помощью статического метода Settings::self(). Рассмотрим фрагмент исходного
тического метода Settings::self(). Рассмотрим фрагмент исходного
+
 
текста класса KApp4, управляющий созданием диалогового окна
 
текста класса KApp4, управляющий созданием диалогового окна
 
настроек:
 
настроек:
Строка 276: Строка 258:
 
dialog->setAttribute( Qt::WA_DeleteOnClose );
 
dialog->setAttribute( Qt::WA_DeleteOnClose );
 
dialog->show();</source>
 
dialog->show();</source>
 +
[[Изображение:LXF108 77 1.png|thumb|300px|Рис. 4. Система настройки программы KApp4.]]
 
Здесь создается объект dialog класса KConfigDialog, который
 
Здесь создается объект dialog класса KConfigDialog, который
реализует диалоговое окно. Конструктору класса передается указа-
+
реализует диалоговое окно. Конструктору класса передается указатель на объект Settings. Далее создается объект generalSettingsDlg
тель на объект Settings. Далее создается объект generalSettingsDlg
+
 
класса QWidget. Он должен стать главной страницей окна настроек.
 
класса QWidget. Он должен стать главной страницей окна настроек.
Внешний вид объекта generalSettingsDlg задается методом ui_prefs_
+
Внешний вид объекта generalSettingsDlg задается методом ui_prefs_base.setupUi() (так же, как и в Qt 4). Затем, с помощью метода
base.setupUi() (так же, как и в Qt 4). Затем, с помощью метода
+
 
addPage() новая страница добавляется в окно настроек. Остается
 
addPage() новая страница добавляется в окно настроек. Остается
только связать сигнал settingsChanged объекта dialog с одноимен-
+
только связать сигнал settingsChanged объекта dialog с одноименным слотом объекта m_view (рабочая область окна программы).
ным слотом объекта m_view (рабочая область окна программы).
+
 
Обработчик сигнала settingsChanged может извлекать данные об
 
Обработчик сигнала settingsChanged может извлекать данные об
изменениях настроек из строки, переданной ему в качестве пара-
+
изменениях настроек из строки, переданной ему в качестве параметра, или непосредственно из объекта Settings, который существует глобально (именно так и поступает слот settingsChanged()
метра, или непосредственно из объекта Settings, который суще-
+
ствует глобально (именно так и поступает слот settingsChanged()
+
 
в рассматриваемой программе). Взаимоотношения между окном
 
в рассматриваемой программе). Взаимоотношения между окном
 
KConfigDialog, объектом Settings и рабочей областью окна можно
 
KConfigDialog, объектом Settings и рабочей областью окна можно
 
проиллюстрировать графически (рис. 4).
 
проиллюстрировать графически (рис. 4).
  
Скорее всего, разработчики KDE 4 почувствовали то же, что чув-
+
Скорее всего, разработчики KDE 4 почувствовали то же, что чувствуете сейчас вы: программирование всех этих классов настройки
ствуете сейчас вы: программирование всех этих классов настройки
+
вручную слишком утомительно. Поэтому они решили автоматизировать процесс. Для создания класса Settings и его вспомогательного
вручную слишком утомительно. Поэтому они решили автоматизиро-
+
класса была использована специальная консольная утилита – kconfig_compiler. На самом деле это, конечно, не компилятор, а генератор
вать процесс. Для создания класса Settings и его вспомогательного
+
класса была использована специальная консольная утилита – kconfig_
+
compiler. На самом деле это, конечно, не компилятор, а генератор
+
 
исходных текстов, которые потом компилируются GCC. Исходниками
 
исходных текстов, которые потом компилируются GCC. Исходниками
 
для kconfig_compiler являются два файла – kapp4.kcfg и kapp4.kcfgc.
 
для kconfig_compiler являются два файла – kapp4.kcfg и kapp4.kcfgc.
Строка 308: Строка 283:
 
понять, как он выглядит на самом деле, нужно выбрать команду
 
понять, как он выглядит на самом деле, нужно выбрать команду
 
View Document Source. Основные тэги файла *.kcfg – это <kcfgfile>,
 
View Document Source. Основные тэги файла *.kcfg – это <kcfgfile>,
<group> и <entry>. Тэг <kcfgfile> принимает в качестве параме-
+
<group> и <entry>. Тэг <kcfgfile> принимает в качестве параметра имя файла, где будут сохраняться настройки программы. Тэг
тра имя файла, где будут сохраняться настройки программы. Тэг
+
 
<group> описывает группу настроек. Его дочерние элементы – тэги
 
<group> описывает группу настроек. Его дочерние элементы – тэги
<entry> – представляют собой отдельные настройки (имя перемен-
+
<entry> – представляют собой отдельные настройки (имя переменной, в которой будет храниться значение конфигурационного параметра, тип данных, имя настройки, предназначенное для пользователя и значение по умолчанию). Кроме того, файлы *.kcfgc содержат указания для генератора kconfig_compiler. Их можно сравнить
ной, в которой будет храниться значение конфигурационного пара-
+
метра, тип данных, имя настройки, предназначенное для пользова-
+
теля и значение по умолчанию). Кроме того, файлы *.kcfgc содер-
+
жат указания для генератора kconfig_compiler. Их можно сравнить
+
 
с Make-файлами GCC.
 
с Make-файлами GCC.
  

Текущая версия на 18:35, 24 августа 2009

KDE4

Содержание

[править] KDE 4 под микроскопом

ЧАСТЬ 1 Считаете, что для KDE 4 мало приложений? В ваших силах исправить ситуацию – благодаря новой серии учебников от Андрея Боровского!

Два года назад LXF публиковал цикл статей о программировании для KDE 3 (LXF8185). Тогда это был зрелый рабочий стол, который готовился уступить место KDE 4, и писать о нем было легко, не не слишком интересно. Легко – поскольку KDE 3 на тот момент был хорошо (даже очень хорошо) документирован, а также потому, что существовало много примеров (в том числе написанных мною самим). С другой стороны, было понятно, что цикл разработки KDE 3 практически завершен, и в статьях о нем не удастся отразить живые моменты рождения новых технологий.

С KDE 4 все обстоит иначе. Его первый стабильный релиз появился в начале этого года, и сейчас KDE 4 активно развивается. Далеко не все идеи разработчиков получили окончательное воплощение; по-видимому, и сам список технологий, используемых в KDE 4, будет со временем меняться – я, например, не уверен, что система Decibel, о которой будет сказано ниже, войдет в последующие релизы. Что же касается документации и примеров, то стоит ли говорить, что для многих частей KDE 4 и то, и другое существует либо в зачаточной стадии, либо вовсе отсутствует. Именно поэтому писать о KDE 4 гораздо интереснее. У нас есть возможность проследить глазами программиста рождение нового рабочего стола, с которым пользователи Linux будут жить несколько ближайших лет. Как и в случае с Qt 4, мы будем предполагать, что вы уже знакомы с разработкой для KDE 3. На всякий случай, уроки в формате PDF есть на DVD этого номера.

[править] А внутри у ней плазма

Библиотеки Qt 4.x во многом революционны, и было бы странно, если бы разработчики KDE 4 не подхватили этот «трудовой порыв». На внешних красотах KDE 4, усиленных мощью 3D-ускорителей, мы останавливаться не будем, а скорее поднимем капот (или снимем кожух?) и посмотрим, что же находится внутри. Один из важнейших элементов KDE, который сразу бросается в глаза (в нескольких смыслах слова) – это Plasma. С точки зрения программиста, она – развитие Qt Graphics View Framework (LXF105). Система Corona расширяет возможности QGraphicsScene, добавляя концепцию апплетов. В результате с элементами графической сцены (т.е. рабочего стола) можно связывать мини-приложения. Изначально разработчики Plasma ориентировались на Qt 4.2, в которой, напомню, еще не было встраиваемых виджетов; в результате пришлось придумывать аналогичный механизм для внедрения пиктограмм и кнопок. Теперь, когда данный функционал появился в самой Qt, можно ожидать более широкого использования встраиваемых виджетов в будущих версиях Plasma.

Минуя другие состояния вещества, перейдем от Plasma к технологии Solid. Это – кросс-платформенная подсистема, предназначенная для работы с устройствами. Правда, Solid не позволяет KDE-приложениям управлять ими, но предоставляет достаточно информации, чтобы программа могла подобрать нужные административные средства самостоятельно.

Еще одна интересная и пока что довольно загадочная новинка KDE 4 – Phonon. Это переносимая мультимедиа-подсистема, поставляемая с Qt начиная с версии 4.4. API Phonon состоит из классов высокого уровня, которые унифицируют доступ к различным библиотекам, связанным с мультимедиа. Судя по документации (которая на момент написания статьи была еще не завершена), важную роль в Phonon играют концепция прозрачного доступа к мультимедиа-ресурсам, независимо от того, где они расположены, и унаследованная от Qt система «модель-контроллер-вид».

Технология под названием Decibel должна упростить жизнь разработчикам IP-телефонов, видеофонов, чатов и т.п. Она написана с использованием чистого Qt 4 (т.е. не зависит от KDE), включает в себя реализацию Telepathy и многих других полезных вещей, но, судя по сайту проекта (http://decibel.kde.org), работа над ним застопорилась примерно год назад. Текущая версия – 0.5, что будет дальше – посмотрим.

[править] Инструменты разработчика

Чтобы программировать для KDE 4, нам, конечно, понадобится сама среда. Проще всего воспользоваться дистрибутивом, в котором KDE 4 доступен по умолчанию, но и тут могут возникнуть неожиданные проблемы. Например, в «живом» OpenSUSE 11.0 KDE Four Live с KDE 4.1 Beta2 обнаружилась одна серьезная и надоедливая ошибка – любое приложение KDE 4, выводящее стандартное диалоговое окно, вызывает фатальный сбой в KNotify (о чем тут же сообщает еще один диалог). Поэтому нам придется довольствоваться KDE 4.04, входящим в состав OpenSUSE 11.0. Помимо собственно графической среды, нам, разумеется, понадобятся пакеты разработчика Qt 4.x и KDE 4.x.

На момент написания этой статьи стабильного KDevelop 4 еще не существовало, а нестабильный работал только с тестовой версией KDE 4.1, от использования которой мы с вами отказались. В Сети можно найти трюки, с помощью которых можно создавать приложения KDE 4 в KDevelop 3.x, но мы на них останавливаться не будем: думаю, что KDevelop 4 уже скоро обретет стабильность, и данные советы морально устареют. Лучше потратим сэкономленную журнальную площадь на KDevelop 4, когда он выйдет. Пока же будем применять инструменты низкого уровня: это позволит нам глубже проникнуть в суть вещей в KDE 4. Не считая стандартных инструментов разработчика, нам понадобятся две консольные утилиты: cmake и kapptemplate – мастер, с вызова которого и начинается процесс разработки. Kapptemplate создает заготовки для простого приложения KDE, приложения KDE со сложным главным окном или KPart.

Далее утилита просит указать имя и расположение нового проекта. Программа также захочет «познакомиться» – узнать ваши имя и e-mail. В этом смысле kapptemplate отличается крайней навязчивостью и задает личные вопросы при каждом запуске.

Директория, в которой kapptemplate сохраняет файлы заготовки программы, содержит много интересного (об этом – чуть позже), но в ней отсутствуют Make-файл и сценарий configure, то есть те скрипты, которые мы привыкли использовать для сборки программ KDE 3. Здесь нам на помощь приходит CMake. Этот кросс-платформенный независимый инструмент от компании Kitware стал частью инструментария KDE 4 совсем недавно. Утилита cmake выполняет для проектов KDE (и не только KDE) ту же работу, что qmake для Qt – т.е. создает Make-файл проекта. Cmake вызывает qmake по ходу процесса, и вы должны убедиться, что утилита с таким именем в вашей системе относится к Qt 4, а не 3.x. Для этого наберите в окне консоли:

(thumbnail)
Рис. 1. Минималистичное приложение KDE 4.
qmake --version

Если qmake «не тот», ситуацию следует исправить с помощью переменной PATH. В самом простом случае (который мы и рассматриваем) для генерации Make-файлов для проекта KDE 4 достаточно скомандовать

cmake <project_path>

где project_path – это путь к проекту. Имейте в виду, что cmake создает выходные файлы, в том числе и Makefile, не в project_path, а в той директории, откуда он был вызван. Теперь, наконец, можно скомандовать

make

и насладиться окном нашего первого приложения KDE 4 (рис. 1). Что же это за зверь такой, сурово указывающий на несвежесть файлов проекта?

Проект CMake: что внутри?

Если даже раньше вы никогда не работали с CMake, то после использования данной утилиты должны почувствовать, насколько она удобна. Создать Make-файлы для стандартного проекта с помощью CMake просто, но вы наверняка хотите знать, как можно влиять на этот процесс – например, добавить ссылки на разделяемые библиотеки? В qmake для этого потребовалось бы отредактировать файл *.pro, а его аналогом в CMake служит CMakeLists.txt. Синтаксис CMakeLists.txt довольно сложен, поэтому мы рассмотрим только самые важные элементы. Каждая строка файла содержит команду и ее аргументы, перечисляемые в круглых скобках. Так, команда project() указывает имя проекта. Здесь можно также задать язык программирования: С, CXX, Java. Команда find_package() находит и загружает данные внешнего пакета. Например,

find_package(KDE4 REQUIRED)

указывает, что требуется загрузить пакет KDE4. Опция REQUIRED уточняет, что без него сборка проекта невозможна (логично, не правда ли?). После загрузки пакета KDE4 файлу настройки CMake становятся доступны определенные в нем переменные и команды. Например, команда Include_directories() использует переменные KDE4_INCLUDES и QT_INCLUDES. Команда kde4_add_ui_files() не относится к числу встроенных в CMake – она также добавляется пакетом KDE4.

Команда target_link_libraries() (на этот раз – стандартная) сообщает, какие библиотеки следует подключить к данной цели сборки (она задается первым аргументом). Команда получает имена библиотек из переменной KDE4_KDEUI_LIBS, которая определена в пакете KDE4.

С помощью файла CMakeLists.txt настоящие мастера могут творить чудеса, однако если премудрости его синтаксиса вас пугают, можете утешиться тем, что вам вовсе не обязательно знать их все. Если вы используете мастер генерации проектов KDE 4, то по большей части настройка файла CMakeLists.txt будет сводиться к незначительному редактированию уже имеющейся

[править] Через увеличительное стекло

Если ваша программа называется kapp4, то объявление класса главного окна содержится в файле kapp4.h (а его методы – в kapp4. cpp). Класс, реализующий центральный элемент главного окна – KApp4View – располагается в файлах kapp4view.h/kapp4view.cpp и наследует от Ui::kapp4view_base, объявление которого (файл ui_ kapp4view_base.h) генерируется автоматически на основе описания интерфейса программы, содержащегося в kapp4view_base.ui. В этой структуре нельзя не заметить влияния Qt 4.x, и (как вы, наверное, уже догадались) класс kapp4view_base.ui не является потомком QWidget, но содержит инструкции, позволяющие настроить таковой (LXF104). Помимо kapp4view_base.ui, в нашем проекте есть еще один ui-файл – prefs_base.ui, который содержит описание интерфейса окна настроек. Забегая вперед, отмечу, что в KDE 4 вы «бесплатно» получаете мощную систему конфигурации приложения пользователем (правда, все равно уступающую таковой в программе-часах из LXF106).

Вы, наверное, уже озадачились вопросом: как редактировать ui-файлы, если KDevelop отсутствует? Отвечаем: для визуального проектирования интерфейса можно воспользоваться редактором Qt Designer 4.x – он поддерживает и виджеты KDE 4. Файлы settings.h и settings.cpp содержат, соответственно, объявление и определение класса Settings. Он наследует от KConfigSkeleton и является основой движка настройки нашего приложения. Наконец, файл main.cpp, как нетрудно догадаться, предоставляет функцию main() нашей программы.

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

int main(int argc, char **argv) {
KApplication app;
KApp4 *widget = new KApp4;
widget->show();
return app.exec();
}

Класс KApp4 реализует главное окно нашего приложения. Мы не сообщаем объекту app класса KApplication, что widget указывает на главный визуальный объект программы. Рассмотрим объявление Kapp4 подробнее:

class KApp4 : public KXmlGuiWindow
{
Q_OBJECT
public:
/**
* Default Constructor
*/
KApp4();
/**
* Default Destructor
*/
virtual ~KApp4();
private slots:
void fileNew();
void optionsPreferences();
private:
void setupActions();
private:
Ui::prefs_base ui_prefs_base ;
KApp4View *m_view;
QPrinter *m_printer;
KToggleAction *m_toolbarAction;
KToggleAction *m_statusbarAction;
};

Класс главного окна является потомком KXmlGuiWindow, который происходит от класса KMainWindow, наследующего от QMainWindow, наряду с KXmlGuiBuilder и KXmlGuiClient. Ниже приводится листинг конструктора класса главного окна

KApp4::KApp4()
: KXmlGuiWindow(), m_view(new KApp4View(this)), m_printer(0) {
// accept dnd
setAcceptDrops(true);
// tell the KXmlGuiWindow that this is indeed the main widget
setCentralWidget(m_view);
// then, setup our actions
setupActions();
// add a status bar
statusBar()->show();
// a call to KXmlGuiWindow::setupGUI() populates the GUI
// with actions, using KXMLGUI.
// It also applies the saved mainwindow settings, if any, and ask the
// mainwindow to automatically save settings if changed: window size,
// toolbar position, icon size, etc.
setupGUI();
}

Я специально не стал убирать из листинга комментарии, добавленные в него программой-генератором, чтобы показать, что файлы-заготовки, созданные kapptemplate, не только освобождают нас от рутинной работы, но и сообщают полезную для новичков информацию о том, что делают вызываемые функции. Для настройки внешнего вида главного окна, как и в KDE 3, используется система KXMLGUI. Напомню, что главное окно хранит данные о меню, панелях инструментов и командах в файлах *ui.rc, имеющих формат XML. Для нашего приложения тоже был создан такой – это kapp4ui. rc, расположенный в той же директории, что и исполняемый файл. Тем не менее, при каждом запуске программы на консоль будет выводиться сообщение о том, что файл kapp4ui.rc не найден (это не приводит к завершению программы, поскольку, не найдя свой собственный rc-файл, приложение берет стандартный из KDE 4). Наша программа не может найти файл kapp4ui.rc потому, что ищет его не там, где он лежит. Глобально установленные приложения, доступные всем пользователям, хранят свои файлы *ui.rc в общедоступной директории (например, /usr/share/kde4/apps/имя_приложения). Для сохранения ваших персональных настроек следует воспользоваться каталогом ~/.kde4/share/apps/имя_приложения.

[править] Система настройки

(thumbnail)
Рис. 2. Окно настройки программы KApp4.
(thumbnail)
Рис. 3. Смена оформления KApp4.

Выше я уже упоминал о том, что стандартный проект приложения KDE 4 по умолчанию снабжается системой настройки. Ее можно разделить на две части: настройка панелей инструментов, сочетаний горячих клавиш – с одной стороны, и конфигурация специфических параметров работы приложения – с другой. Особенность настройки первого типа заключается в том, что, по существу, она одинакова для всех приложений KDE и может быть легко формализована. Однако разработчики KDE на этом не успокоились и сделали все возможное, чтобы охватить и процесс создания средств специфической настройки приложений. Окно специальных настроек (рис. 2) открывается по команде Configure KApp4... меню Settings.

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

Глобальные установки хранятся в директории /usr/share/kde4/config, а локальные – в ~/.kde4/share/config. После нескольких запусков программы KApp4 я нашел в ней два файла: KApp4rc, где хранятся параметры рабочей области, и kapp4rc, содержащий данные о геометрии главного окна и видимости его элементов. Следует отметить, что многие программы KDE 4 хранят свои параметры конфигурации сразу в нескольких файлах.

Для управления настройками создается глобальный объект класса Settings. Получить указатель на него можно с помощью статического метода Settings::self(). Рассмотрим фрагмент исходного текста класса KApp4, управляющий созданием диалогового окна настроек:

KConfigDialog *dialog = new KConfigDialog(this, "settings",Settings::self());
QWidget *generalSettingsDlg = new QWidget;
ui_prefs_base.setupUi(generalSettingsDlg);
dialog->addPage(generalSettingsDlg, i18n("General"), "package_setting");
connect(dialog, SIGNAL(settingsChanged(QString)), m_view, SLOT(settingsChanged()));
dialog->setAttribute( Qt::WA_DeleteOnClose );
dialog->show();
(thumbnail)
Рис. 4. Система настройки программы KApp4.

Здесь создается объект dialog класса KConfigDialog, который реализует диалоговое окно. Конструктору класса передается указатель на объект Settings. Далее создается объект generalSettingsDlg класса QWidget. Он должен стать главной страницей окна настроек. Внешний вид объекта generalSettingsDlg задается методом ui_prefs_base.setupUi() (так же, как и в Qt 4). Затем, с помощью метода addPage() новая страница добавляется в окно настроек. Остается только связать сигнал settingsChanged объекта dialog с одноименным слотом объекта m_view (рабочая область окна программы). Обработчик сигнала settingsChanged может извлекать данные об изменениях настроек из строки, переданной ему в качестве параметра, или непосредственно из объекта Settings, который существует глобально (именно так и поступает слот settingsChanged() в рассматриваемой программе). Взаимоотношения между окном KConfigDialog, объектом Settings и рабочей областью окна можно проиллюстрировать графически (рис. 4).

Скорее всего, разработчики KDE 4 почувствовали то же, что чувствуете сейчас вы: программирование всех этих классов настройки вручную слишком утомительно. Поэтому они решили автоматизировать процесс. Для создания класса Settings и его вспомогательного класса была использована специальная консольная утилита – kconfig_compiler. На самом деле это, конечно, не компилятор, а генератор исходных текстов, которые потом компилируются GCC. Исходниками для kconfig_compiler являются два файла – kapp4.kcfg и kapp4.kcfgc. Если вы откроете файл kapp4.kcfg в стандартном окне просмотра Dolphin (мы ведь работаем в KDE 4, не так ли?), то увидите только невразумительное:

color of the background black color of the foreground yellow size of a ball 2

Дело в том, что kapp4.kcfg – файл в формате XML. Чтобы понять, как он выглядит на самом деле, нужно выбрать команду View Document Source. Основные тэги файла *.kcfg – это <kcfgfile>, <group> и <entry>. Тэг <kcfgfile> принимает в качестве параметра имя файла, где будут сохраняться настройки программы. Тэг <group> описывает группу настроек. Его дочерние элементы – тэги <entry> – представляют собой отдельные настройки (имя переменной, в которой будет храниться значение конфигурационного параметра, тип данных, имя настройки, предназначенное для пользователя и значение по умолчанию). Кроме того, файлы *.kcfgc содержат указания для генератора kconfig_compiler. Их можно сравнить с Make-файлами GCC.

Что ж, для первого раза, наверное, достаточно. Загляните в те файлы, на которые нам не хватило места, а если вы достаточно храбры – попробуйте модифицировать программу, вооружившись только что полученными знаниями.

Персональные инструменты
купить
подписаться
Яндекс.Метрика