Программирование в AmigaOS. Часть вторая

Графический Интерфейс AmigaOS (GUI)

Андрей Черешнев

2. Введение

Графический интерфейс, является неотъемлемой частью AmigaOS. С каждой новой версией ОС процесс создания GUI для программ упрощается, а его возможности увеличиваются, например появление стандартных риквесторов и интерфейса BOOPSI. Это позволяет программистам больше уделять времени логике программы, а графический интерфейс органично с ней связывать.

2.1 Элементы AmigaOS GUI

Intuition - так называется подсистема AmigaOS, отвечающая за графический интерфейс.

Workbench - графический интерфейс для AmigaDOS.

Preferences - программы, которые позволяют устанавливать конфигурацию.

BOOPSI - подсистема Intuition, представляет из себя объектно-ориентированный системный интерфейс. С помощью него, например, работает MUI.

Библиотеки:

gadtools.library - библиотека, которая применяется при создании GUI стандартными средствами AmigaOS.

asl.library - применяется для работы с риквесторами запроса на выбор файла, группы файлов, шрифта и т.д.

graphics.library - библиотека для работы с графикой (спрайты, анимация, шрифты и т.д.)

workbench.library - для программ использующих возможности Workbench - AppWindow, AppIcon, AppMenuItem.

icon.library - для работы с иконками.

2.2 Компоненты Intuition

Основные составляющие графического интерфейса программ:

Screens - на "экранах" располагаются окна программ. Программы могут сами создавать экраны для своих нужд (custom или public), а также пользоваться уже существующими общими (public) экранами, например "Workbench Screen".

Windows - основная рабочая область программы.

Menus - линейка меню программы. Обычно содержит список всех возможных действий программы.

Gadgets - графические символы, которые представляют из себя управляющие элементы, например кнопки или стрелки прокрутки.

Requesters - окна для вывода различных сообщений, запросов.

Input events - события, которые принимает и обрабатывает Intuition, например движения мышью, нажатие на кнопку в окне.

2.3 MUI - "волшебный" интерфейс

AmigaOS через BOOPSI предлагает новый подход в создании программ. Он называется объектно-ориентированный. Наиболее полно реализует эту возможность интерфейс MUI. MUI представляет из себя набор библиотек, главная - muimaster.library, она же использует остальные. И набора "классов" в подкаталоге LIBS:mui/. Также интерфейс содержит программу "MUI" для настройки внешнего вида программ и программу "PSI", которая позволяет создавать "общие" экраны для MUI программ.

2.3.1 Объектно-Ориентированное Программирование (ООП)

Наверняка многие читатели уже знакомы с понятием ООП. Много книг написано на эту тему, в основном о C++. Язык С++ считается довольно трудным для изучения, а грамотное написание программ на этом языке возможно только после специального обучения в соответствующих заведениях, поэтому MUI использует только основные догмы ООП и язык С.

Основные понятия ООП - "класс" и "объект". Класс позволяет рассматривать некоторые логически связанные данные и функции программы как одно целое (единый организм) и затем создавать отдельные экземпляры этого класса ("организма") которые начнут новую "жизнь", они называются объектами. Например функцию вывода текста и переменную содержащую текст можно представить в виде класса "Text", затем создать несколько объектов этого класса, причем каждый объект будет содержать свой текст (для него отводится новая память), а функция вывода текста останется та же самая (объект содержит ссылки на функции), т.е. в памяти будет только одна копия функции вывода текста для всех созданных объектов класса "Text"! Теперь этой функции не нужен аргумент (указатель на строку) т.к. вызывая её из каждого созданного объекта, текст будет печататься из переменной соответствующего объекта.

Переменная объекта, которая содержит текст называется атрибутом объекта, функция - методом, вызов этой функции - посылка объекту сообщения или выполнение метода.

Допустим, мы хотим чтобы объекты выводили текст в определённых координатах (x,y) курсивом. Для этих целей существует "наследование". Мы используем накопленный "опыт" класса Text и на основе его атрибутов и методов создаём новый класс "NewText" он будет состоять из двух атрибутов (x,y) и одного метода (вывод курсивом), а сами объекты класса "NewText" будут содержать в себе три атрибута (x,y, сам текст) и использовать два метода (вывод и вывод курсивом). Класс "Тext" в этом случае называют классом предком или родительским классом, а класс "NewText" потомком класса "Text".

2.3.2 Встроенные классы

MUI содержит множество классов необходимых для создания GUI. Эти классы представлены в виде дерева иерархии. Объекты наследуют все методы и атрибуты родительского класса и классов стоящих выше в иерархии. Например объект класса Image, наследует методы и атрибуты классов Area и Notify.

 rootclass                - базовый класс BOOPSI
  |
  Notify                  - механизм извещения объектов
   |
   +--Application         - главный класс программы
   +--Window              - окно программы
   +--Area                - базовый класс для всех GUI элементов
       |
       +--Rectangle       - чертит прямоугольники для визуального разделения
       +--Image           - графическое изображение
       +--Text            - вывод текста
       +--String          - строка ввода
       +--Prop            - создаёт пропорциональный gadget(ползунок)
       +--Gauge           - индикатор процесса(измеритель)
       +--Scale           - процентная шкала
       +--Boopsi          - интерфейс для BOOPSI классов
       +--Colorfield      - закрашенная область
       +--List            - создаёт линейный список
       |   |
       |   +--Floattext   - "плавающий" список
       |   +--Volumelist  - список томов
       |   +--Scrmodelist - список экранных режимов
       |   +--Dirlist     - список файлов
       |
       +--Group           - группирует GUI элементы и отвечает за их расположение
           |
           +--Virtgroup   - управляет виртуальными группами
           +--Scrollgroup - управляет виртуальными группами с линейками прокрутки
           +--Scrollbar   - создаёт линейку прокрутки
           +--Listview    - создаёт список
           +--Radio       - переключатели (радио-кнопки)
           +--Cycle       - раскрывающися список выбора
           +--Slider      - создаёт ползунок
           +--Coloradjust - создаёт RGB ползунок (колесо)
           +--Palette     - gadget палитры цветов

MUI не имеет отдельных классов для кнопки (Button) и пометки (СheckMark) так как они "находятся" в классе Area. Подробную информацию по каждому классу можно получить из файла MUI/Autodocs/MUI_имя_класса.doc.

2.3.3 Создание программы

Программа может состоять из большого количества объектов или дерева объектов. Это дерево создаётся путем "присоединения" одного объекта к другому.

В основе дерева лежит объект класса Application. Он берёт на себя функции контроля окон программы, различными событиями, Arexx интерфейсом. Один объект этого класса должен обязательно создаваться в программе. К нему присоединяют (SubWindow) объекты класса Window.

Объекты класса Window управляют созданием, закрытием, перемещением, изменениями размера окна и обновлением информации в окне. Для того чтобы в окне появились GUI объекты, его нужно "снабдить" (WindowContents) так называемым корневым (root) объектом. Обычно, этим объектом является объект класса Group.

Одной из самых важных особенностей MUI, является динамическое расположение GUI элементов в окне. Программисту не нужно заботиться о "настоящих" размерах и координатах объекта. Всё, что требуется, это определить некоторые прямоугольные области, в которые помещаются кнопки, списки и другие объекты. Для этих целей предназначены объекты класса Group, они не видны на экране, их задача группировать "присоединённые" (Child) к ним объекты и размещать их в окне горизонтально, вертикально, в колонках, в ярлыках.

Пример дерева объектов MUI программы:

пример

Только три типа объекта могут присоединять к себе другие, это:

  1. Application - присоединяет объекты класса Window.
  2. Window - только один объект, потомок класса Area.
  3. Group - один или более потомков класса Area.

2.3.4 Принятые обозначения

В описании атрибута класса содержатся следующие буквы: [ISG]

Пример описания: MUIA_Window_Open -- (V4 ) [.SG], BOOL

Атрибут содержит значение типа BOOL, может читаться/устанавливаться, но не может быть установлен во время создания объекта.

2.3.5 Создание и управление объектами встроенных MUI классов

Для того чтобы создать объект используется функция MUI_NewObject(), её прототип:

Object *MUI_NewObject(STRPTR class, Tag tag1, ..., TAG_DONE);

Аргумент class - имя класса, например "MUIC_Window". tag1, tag2, ... - атрибуты объекта, которые нужно установить при его создании, например tag1 можно представить в виде "MUIA_Window_Title, title," для установки заголовка окна. Пример создания объекта класса Window:

MyWindow = MUI_NewObject(MUIC_Window,
                         MUIA_Window_Title, "Hello",
                         WindowContents, MyGroup,
                         TAG_DONE);

Атрибут WindowContents содержит указатель на присоединяемую к окну группу (MyGroup) объектов.

Как только объект создан, ему можно посылать сообщения функцией DoMethod(), устанавливать и получать значения атрибутов объекта функциями set() и get().

2.3.6 Удаление объектов

Объекты удаляются с помощью функции MUI_DisposeObject(), прототип:

void MUI_DisposeObject(Object *obj);

Если к объекту "присоединялись" другие объекты, то они также по цепочке удаляются из памяти. Таким образом, удаляя объект класса Application, мы удаляем все объекты программы. Нужно помнить, что если сам объект присоединяли, то его удалят нельзя, это не относится к динамически присоединённым объектам. Пример:

MUI_DisposeObject(app);

Удаляет объект app класса Application, присоединённые к нему окна - атрибуты "SubWindow", а также Group объекты этих окон - "WindowContents".

2.3.7 Функции DoMethod() и set()

Функция DoMethod() посылает объекту сообщение (выполняет метод). Прототип:

ULONG DoMethod(Object *obj, ULONG Method, ...);

obj - объект, Method - имя выполняемого метода. Далее в списке аргументов следуют аргументы к самому методу. Методы могут быть как класса которому принадлежит объект, так и классов предков. Примеры:

DoMethod(MyWindow, MUIM_Window_ToFront);

Перемещает окно MyWindow на передний план.

DoMethod(app, MUIM_Application_AboutMUI, MyWindow);

Выполняет метод объекта app класса Application, аргумент MyWindow говорит о том, что окно "About MUI" будет появлятся по центру относительно MyWindow.

Функция set() устанавливает атрибуту объекта заданное значение. Атрибуты могут быть как класса которому принадлежит объект, так и классов предков. Пример:

set(MyWindow, MUIA_Window_Open, TRUE);

Устанавливает атрибуту MUIA_Window_Open значение TRUE, т.е. выполнение этой операции приводит к появлению окна MyWindow на экране.

2.3.8 Механизм извещения объектов

Механизм извещения объектов - это способ контроля объектов и установки связей между объектами. Он основывается на том, что значения атрибутов объекта определяют его текущее состояние или свойства. "Извещение" позволяет устанавливать реакцию на изменение состояния объекта.

Значения атрибутов объекта могут изменяться или программистом, функцией set(), или действиями пользователя, например во время изменения положения ползунка в окне, атрибут "MUIA_Slider_Level" объекта класса Slider будет динамически изменять своё значение. Таким образом, мы можем связать ползунок и объект класса Gauge (индикатор), чтобы индикатор показывал текущее положение.

Для извещения применяется метод MUIM_Notify, он присутсвует во всех MUI объектах. Рассмотрим его подробнее:

DoMethod(obj,
         MUIM_Notify, ULONG TrigAttr, ULONG TrigVal,
         DestObj,
         ULONG FollowParams,
         /* ... */);

Примеры:

Объект MySlider связываем с объектом MyGauge. При изменении значения MUIA_Slider_Level, выполняется метод MUIM_Set объекта MyGauge, он устанавливает атрибут MUIA_Gauge_Current в значение MUIA_Slider_Level. В итоге, когда мы перемещаем ползунок, индикатор одновременно с ним изменяет свои показания (см. рисунок):

пример

DoMethod(MySlider,
         MUIM_Notify, MUIA_Slider_Level, MUIV_EveryTime,
         MyGauge,
         3,
         MUIM_Set, MUIA_Gauge_Current, MUIV_TriggerValue);

В следующем примере объект MyWindow контролирует поведение объекта app. Когда атрибут MUIA_Window_CloseRequest объекта MyWindow примет значение TRUE (окно закрыто) выполнится метод MUIM_Application_ReturnID объекта app с аргументом MUIV_Application_ReturnID_Quit (закрытие приложения). Таким образом, когда мы закрываем окно, программа прекращает свою работу - происходит выход из цикла обработки сообщений (см. пример MUI программы):

DoMethod(MyWindow,
         MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
         app,
         2,
         MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

2.3.9 Пример MUI программы - "HelloWorld!"

/* файл hello_world!.c */

#include <libraries/mui.h>

#include <proto/muimaster.h>
#include <proto/exec.h>

#include <stdio.h>
#include <stdlib.h>

struct Library *MUIMasterBase; /* указатель на библиотеку */

int main(void)
{
    /* объекты нашей программы: */
    Object  *app, *TX_helloworld, *GROUP_ROOT, *WI_helloworld;

    /* "открываем" библиотеку MUI */
    MUIMasterBase = OpenLibrary("muimaster.library", MUIMASTER_VMIN);
    if(!MUIMasterBase)
    {
        puts("Can't open muimaster.library");
        return(20);
    }

    /* Для удобства, вместо прямого вызова функции MUI_NewObject(),
     * в файле "mui.h" определены макросы типа:
     *
     * #define TextObject   MUI_NewObject(MUIC_Text
     * #define End          TAG_DONE)
     *
     * Атрибуты и методы класса можно найти в файле "Аutodocs/
     * MUI_имя_класса.doc". Если у вас редактор GoldEd и настроена
     * система "Reference": кликните на слове, например на "MUIA_Font",
     * и в меню "Search" выберите "Reference", в итоге, получите
     * его подробное описание.
     *
     * Создаем объекты:
     */

    TX_helloworld = TextObject,
            MUIA_Background, MUII_TextBack,
            MUIA_Frame, MUIV_Frame_Text,
            MUIA_Font, MUIV_Font_Big,
            MUIA_Text_Contents, "Hello, World!",
            MUIA_Text_PreParse, "\33c",
            MUIA_Text_SetMin, TRUE,
    End;

    GROUP_ROOT = GroupObject,
            Child, TX_helloworld, /* присоединили объект к группе */
    End;

    WI_helloworld = WindowObject,
            MUIA_Window_Title, "Hello",
            MUIA_Window_ID, 1,
            WindowContents, GROUP_ROOT, /* присоединили группу к окну */
    End;

    app = ApplicationObject,
            MUIA_Application_Title, "HelloWorld!",
            MUIA_Application_Base, "HELLOWORLD!",
            SubWindow, WI_helloworld, /* присоединили окно к программе */
            End;

    if(app)
    {
        DoMethod(WI_helloworld,
                 MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
                 app,
                 2,
                 MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

        /* открываем окно */
        set(WI_helloworld, MUIA_Window_Open, TRUE);

        /*            Цикл обработки сообщений
         *
         * Следующий блок программы выполняет "основную работу" -
         * обрабатывает(посылает сообщения объектам) все события
         * которые получает наша программа. Этот стандартный блок
         * обычно используется программистами без изменений.
         */
        {
            ULONG sigs = 0;

            while (DoMethod(app,MUIM_Application_NewInput,&sigs)
                            != MUIV_Application_ReturnID_Quit)
            {
                if (sigs)
                {
                    sigs = Wait(sigs | SIGBREAKF_CTRL_C);
                    if (sigs & SIGBREAKF_CTRL_C) break;
                }
            }
        }

        /* Блок отработал своё - программа получила сообщение о
         * выходе.
         *
         * Удаляем "главный" объект - "app", а так как мы
         * "присоединили" к нему объект "WI_helloworld", то все
         * объекты по цепочке удалятся:
         */
        MUI_DisposeObject(app);
    }
    CloseLibrary(MUIMasterBase);
    return(0);
}

пример

В результате получилась программа которая обладает всеми возможностями MUI - полностью настраиваемый GUI, что очень важно и для программиста т.к. система сама следит за правильным расположением (размерами) всех настраиваемых пользователем GUI элементов, например шрифтами; сервисом программы "Exchange"; и т.д. Попробуйте "поиграть" со шрифтом программы: в окне программы "MUI" раздел "Windows/Fonts/Big:" выбирайте разные шрифты (размеры). При этом шрифт нашей программы будет меняться автоматически после нажатия на кнопку "Test" в окне программы "MUI".

Следующая статья будет посвящена созданию класса "helloworld", добавим в него меню и кнопки, а также работе с программой MUIBuilder. Её можно взять из Интернет:

http://aminet.net/dev/mui/MUIBuilder22.lha

Эта программа позволяет визуально создавать интерфейс, а затем "переводить" его в строки кода, кстати, объекты для программы "HelloWorld!" были созданы с помощью неё.


© 1998-2006  Андрей Черешнев
Часть третья | Начало
Сайт создан в системе uCoz