![]() |
|||
Руководство разработчика приложений ZuneПредисловиеЧто такое Zune?Zune является объектно-ориентированным набором для разработки приложений с графическим интерфейсом пользователя (GUI). Это практически полный аналог MUI (Magic User Interface), как на уровне API, так и на уровне Look&Feel, самого популярного на Amiga shareware-интерфейса Стефана Штунтца. Таким образом, разработчики знающие MUI, почувствуют себя здесь "как дома", а остальные смогут изучить понятия и особенности, общие для обоих средств. Постулируется, что:
Zune основан на системе BOOPSI (Basic Object Oriented Programming System for Intuition), унаследованной от AmigaOS и используемой в объектно-ориентированном программировании на Си. Классы Zune не являются дочерними по отношению к существующим для элементов интерфейса классам BOOPSI (т.е., не являются простым расширением их возможностей). Напротив, базовым классом (в иерархии Zune) является класс Notify — дочерний относительно корневого класса BOOPSI. ПредпосылкиДля понимания концепции Zune, более чем приветствуется знание парадигмы объектно-ориентированного программирования (ООП). Вы можете воспользоваться Google для поиска и изучения образовательных материалов, посвящённых ООП. Также, желательно, владение такими ключевыми понятиями AROS (и AmigaOS), как список тегов (taglist) и система BOOPSI. Хорошим подспорьем здесь, безусловно, является руководство "Amiga Reference Kernel Manuals" (известное как RKM). Поскольку Zune является аналогом MUI, вся документация, имеющая отношение к MUI, применима и к Zune. В частности, последняя версия инструментария для разработчиков интерфейсов MUI доступна здесь. Среди прочих, в этом LHA-архиве есть 2 документа особенно рекомендуемых к прочтению:
Также этот архив содержит документацию (MUI autodocs), которая является описанием и для всех существующих классов Zune. Реализация BOOPSIКонцепцииКлассКласс (class), по сути, является лишь абстракцией, типом, описывающим объекты этого класса с общими структурой и поведением, и задаётся именем, родительским классом и диспетчером (dispatcher). Описание вводится путем указания типа и свойств класса:
В BOOPSI типом класса является Class * или IClass. ОбъектОбъект является структурной единицей (реализацией) класса. Каждый объект обладает своими свойствами (состоянием), но при этом поведение всех объектов одного класса одинаково. Объект относится к нескольким классам, если исчислять их от его класса до корневого класса rootclass, что определяется свойством наследования. Для объекта типом BOOPSI является Object *. Он не содержит доступных напрямую полей. АтрибутАтрибут находится в связи с структурой данных (переменными состояния) каждого объекта: изменять эти данные непосредственно вы не можете. Возможно только установить или получить значения атрибутов объекта (также называемых свойствами) для изменения его внутреннего состояния. Атрибуты объекта (со стороны системы) ассоциированы с тегами (Tag) (со стороны программиста) (это значения, имеющие тип ULONG и связанные с TAG_USER). Для изменения атрибутов объектов используются функции GetAttr() и SetAttrs(). Атрибуты (один или несколько) могут быть следующих видов:
МетодМетодом в BOOPSI называется функция, которой в виде параметров передаются имя объекта, его класс и сообщение:
Для отправки сообщения объекту используется функция DoMethod(). Сначала метод будет применён к указанному классу. Если в классе определен этот метод, то сообщение будет обработано. В противном случае, будут перебираться родительские классы до тех пор, пока сообщение не будет обработано одним из них, или не будет достигнут rootclass (в этом случае так и не определённое сообщение будет молча отвергнуто). ПримерыРассмотрим основные приёмы объектно-ориентированного программирования с BOOPSI: Получение атрибутаПопробуем запросить данные объекта MUI String:
void f(Object *string)
{
IPTR result;
GetAttr(string, MUIA_String_Contents, &result);
printf("String content is: %s\n", (STRPTR)result);
}
Здесь string - объект, MUIA_String_Contents - получаемый атрибут, &result - указатель на строку с результатом этой операции. К тому же:
В приложениях Zune вместо указанных функций часто используются макросы get() и XGET(). Например: get(string, MUIA_String_Contents, &result); result = XGET(string, MUIA_String_Contents); Установка атрибутаСлегка изменим приведенную выше строку: SetAttrs(string, MUIA_String_Contents, (IPTR)"hello", TAG_DONE);
Вам наверняка покажется полезным макрос set(): set(string, MUIA_String_Contents, (IPTR)"hello"); Однако, только с помощью SetAttrs() вы сможете установить несколько атрибутов за один раз:
SetAttrs(string,
MUIA_Disabled, TRUE,
MUIA_String_Contents, (IPTR)"hmmm...",
TAG_DONE);
Вызов методаРассмотрим наиболее часто применяемый в программах Zune метод, метод обработки событий, вызываемый в основном цикле программы: result = DoMethod(obj, MUIM_Application_NewInput, (IPTR)&sigs);
Hello world
С начала, так с начала. Эта программа не разочарует новичка. Исходный кодРассмотрим наш первый реальный пример:
// gcc hello.c -lmui
#include <exec/types.h>
#include <libraries/mui.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/muimaster.h>
#include <clib/alib_protos.h>
int main(void)
{
Object *wnd, *app, *but;
// Создание GUI: окна wnd, текста Hello world! и кнопки Ok
app = ApplicationObject,
SubWindow, wnd = WindowObject,
MUIA_Window_Title, "Hello world!",
WindowContents, VGroup,
Child, TextObject,
MUIA_Text_Contents, "\33cHello world!\nHow are you?",
End,
Child, but = SimpleButton("_Ok"),
End,
End,
End;
if (app != NULL)
{
ULONG sigs = 0;
// Реакция на элемент закрытия окна и выход по клавише Escape
DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
(IPTR)app, 2,
MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
// Реакция на нажатие кнопки выхода
DoMethod(but, MUIM_Notify, MUIA_Pressed, FALSE,
(IPTR)app, 2,
MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
// Открываем окно wnd
set(wnd, MUIA_Window_Open, TRUE);
// Проверяем, что окно wnd действительно было открыто
if (XGET(wnd, MUIA_Window_Open))
{
// Основной цикл приложения Zune
while((LONG)DoMethod(app, MUIM_Application_NewInput, (IPTR)&sigs)
!= MUIV_Application_ReturnID_Quit)
{
if (sigs)
{
sigs = Wait(sigs | SIGBREAKF_CTRL_C);
if (sigs & SIGBREAKF_CTRL_C)
break;
}
}
}
// Уничтожаем наше приложение со всеми его объектами
MUI_DisposeObject(app);
}
return 0;
}
КомментарииЗамечаниеМы не открываем библиотеки вручную т.к. это делается за нас автоматически. Создание GUI интерфейсаМы использовали макросы для облегчения программирования интерфейса программы. Приложение Zune всегда имеет 1 (и только 1) объект Приложения (ApplicationObject): : app = ApplicationObject, Приложение может иметь 0,1 или более объектов окон WindowObject. Чаще всего окно - одно единственное: : SubWindow, wnd = WindowObject, Будет хорошо, если заголовок окна будет содержать название приложения: : MUIA_Window_Title, "Hello world!", Окно может иметь 1 (и только 1) дочерний объект (Child), обычно это группа (group). Наша группа будет вертикальной (VGroup), это означает, что все входящие в неё дочерние объекты (children) будут группироваться по вертикали: : WindowContents, VGroup, Группа должна иметь, как минимум 1 дочерний объект. В нашем случае, это будет обыкновенный текст (TextObject): : Child, TextObject, В Zune поддерживаются различные escape-коды (ниже, через 33c производится центрирование текста) и перевод каретки ( n ): : MUIA_Text_Contents, "\33cHello world!\nHow are you?", Макрос End должен завершать описание любого макроса вида xxxObject (в нашем случае, TextObject): : End, Теперь добавим в нашу группу второй дочерний объект, кнопку! Помимо мыши, она будет откликаться на комбинацию клавиш RAmiga + O (укажем на это символом подчёркивания до буквы "O"):
: Child, but = SimpleButton("_Ok"),
Завершаем описание группы: : End, Завершаем описание окна: : End, Завершаем описание программы: : End; И что, вы всё ещё нуждаете в графических инструментах для создания GUI ? :-) Обработка ошибокЕсли окажется невозможным создание любого из объектов в структуре описанной нами выше, Zune уничтожит все объекты (включая те, которые удалось создать) и возвратит код ошибки. В обратном случае, вы получите полностью рабочий Zune интерфейс приложения:
: if (app != NULL)
: {
: ...
Если работа приложения завершается, вызывается метод MUI_DisposeObject() с передачей указателя на созданный объект приложения. Это необходимо для уничтожения всех созданных объектов и освобождения всех использованных ресурсов: : ... : MUI_DisposeObject(app); : } Обработка сообщенийОбработка сообщений значительно упрощает задание реакции программы на возникающие события (такие как, нажатие кнопки). Принцип: мы получаем сообщение, когда определённый атрибут определённого объекта примет определённое значение: : DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, Здесь мы ожидаем, когда атрибут MUIA_Window_CloseRequest объекта нашего окна (wnd) будет установлен в TRUE (пользователь нажал кнопку), В этом случае объект приложения получит сообщение, предписывающее ему вернуть код MUIV_Application_ReturnID_Quit на следующей же итерации цикла обработки событий: : (IPTR)app, 2, : MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); Поскольку в этом списке могут быть указаны любые параметры, необходимо указать число дополнительных параметров, передаваемых MUIM_Notify: в этом случае, 2 параметра. В случае c кнопкой "Ok" мы ожидаем, когда атрибут MUIA_Pressed` окажется установленным в FALSE, что будет означать нажатую и отпущенную пользователем кнопку "Ok" (реакция на простое нажатие кнопки является плохой практикой, т.к. вы можете захотеть отпустить кнопку мыши вне кнопки, и таким образом отказаться от действия. К тому же, мы можем и просто захотеть увидеть, как она выглядит в нажатом состоянии). В остальном, всё аналогично предыдущему примеру (посылается сообщение): : DoMethod(but, MUIM_Notify, MUIA_Pressed, FALSE, : (IPTR)app, 2, : MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); Открытие окнаОкно не будет открыто, пока вы не "попросите" Zune об этом: : set(wnd, MUIA_Window_Open, TRUE); Если объекты описанной нами выше структуры были созданы удачно, вы уже должны увидеть окно. Но и эта операция может завершиться с ошибкой! Таким образом, мы не должны забывать о проверке атрибута объекта окна, который должен быть установлен в TRUE: : if (XGET(wnd, MUIA_Window_Open)) Цикл приложенияДорогие друзья, позвольте представить вам идеальный цикл интерфейса Zune: : ULONG sigs = 0; Не забывайте обнулять сигналы (sigs) ... далее показан тестовый цикл приложения с использованием метода MUIM_Application_NewInput: : ... : while((LONG) DoMethod(app, MUIM_Application_NewInput, (IPTR)&sigs) : != MUIV_Application_ReturnID_Quit) Этому методу передаются сигналы событий, которые он должен обработать (сообщения от Wait(), или 0), значение указателя sigs будет изменяться, принимая значения ожидаемых Zune сигналов (очередных сообщений от Wait()) и в результате это значение будет возвращено. Поэтому обнуление sigs в цикле необходимо. Этот механизм возврата значений исторически был единственным способом реакции на события. Однако, поскольку он был слишком "неудобоварим", впоследствии от него стали отказываться в пользу создания отдельных классов и объектно-ориентированной структуры приложения. Тело самого цикла приложения весьма простое. Здесь мы видим лишь ожидание сигналов и обработку нажатия Ctrl + С для обеспечения принудительного выхода из цикла:
: {
: if (sigs)
: {
: sigs = Wait(sigs | SIGBREAKF_CTRL_C);
: if (sigs & SIGBREAKF_CTRL_C)
: break;
: }
: }
ЗаключениеЭта программа позволила вам начать изучение Zune и немного поработать на дизайном GUI приложения, но не более того. СборкаЧтобы собрать эту программу кросс-компилятором i386-aros-gcc, используйте следующую команду: i386-aros-gcc -o hello -D__AROS__ hello.c -lmui Реакция на событияСогласно комментариям к hello.c, приведенным выше, вы должны использовать MUIM_Notify для вызова метода при возникновении ожидаемого вами события. Если же требуется описать более специфичную реакцию программы на события, необходимо воспользоваться одним из следующих алгоритмов:
|
Copyright © 1995-2008, The AROS Development Team. Все права защищены. Amiga© является торговым знаком Amiga Inc. Все прочие торговые знаки принадлежат их собственникам. |