Когда модель объекта компонента ясно определена, вы можете начинать реализацию классов.
Наилучший метод - получить по одному исходному файлу и одному файлу заголовков (header file) для каждого класса и относящихся к нему виртуальных классов. Посмотрите ниже, где больше инофрмации по виртуальным классам.
Вот выдержка из Qt компонента исходной директории:
$ pwd
~/gambas/src/lib/qt
$ ls
CButton.cpp CIconView.cpp CScreen.cpp main.cpp
CButton.h CIconView.h CScreen.h main.h
...
Вы может объявить несколько классов в том же самом файле, но вы должны обычно избегать этого. Все становится яснее, если следовать этому.
Что такое виртуальный класс? Это класс, который представляет
суб-компонент класса, но которому вы не можете ни приписать значения,
ни сослаться на него в переменной. Например, свойство Item
компонента Qt класса ListBox
- это виртуальный класс,
который представляет ListBox
раздел (item).
Виртуальные классы используются только интерпретатором, как типы
данных. Но объект, используемый за ним, это реальный объект, приходящий
из реального, не виртуального класса. Например, свойство Item класса ListBox
сохраняет индекс раздела (item), с которым вы хотите иметь дело в
объекте ListBox
и вернуть этот объект ListBox
. Объект ListBox
становится затем объектом
виртуального класса, который вы не можете сохранить в переменной. Так
что вы должны использовать объект виртуального класса немедленно,
вызывая метод или свойство с ним, сохраненный индекс будет использован
тоже немедленно.
Этот механизм был разработан так, чтобы пользователь манипулировал временными объектами, без необходимости компилирования для их создания. Это НАСТОЛЬКО быстрее!
Заметьте, что имя виртуального класса должно начинаться с точки.
Например, имя виртуального класса, использованного свойством Item
- это
.ListBoxItem
.
Исходный файл класса содержит:
Структура файла заголовка класса следующая:
/* MyClass.h */Включите
#ifndef __MYCLASS_H
#define __MYCLASS_H
main.h
здесь и любое другое включение
необходимое объявлениям, расположенным в этом файле. #include "main.h"Если класс допускает образцы, объявите структуру ваших объектов. Заметьте, что структура должна начинаться с GB_BASE поля, и что другие поля свободны.
typedef
struct {
GB_BASE ob;
...
}
MyClassStruct;
main.c
будет включать файлы, включающие класс, так что он
должен иметь доступ к описанию класса.
#ifndef __CEXAMPLE_CИначе вы можете объявить полезный макрос, который поможет написать реализацию класса. Например, следующая константа делает код более "читабельным". Заметьте, что она может использоваться только том, где декларирован
extern GB_DESC MyClass[];
extern GB_DESC MyVirtualClassDesc[];
_object
, то есть, внутри реализации метода
или свойства. #else
#define THIS ((MyClassStruct *)_object)
#endif
#endif /* __MYCLASS_H */
Структура исходного файла класса следующая:
/* MyClass.c */Включите файл заголовка класса, и любые другие включения файлов, нужных содержимому исходного файла (source file).
#define __CEXAMPLE_C
#includeЕсли ваш класс возбуждает события, вы должны объявить их с помощью макроса DECLARE_EVENT .
#include
...
#include "MyClass.h"
DECLARE_EVENT(FirstEvent);Включите любую статическую функцию, которая может понадобиться вашей реализации.
DECLARE_EVENT(SecondEvent);
...
static void do_job(...)Затем запишите реализацию каждого метода и свойства.
{
...
}
BEGIN_METHOD(...)И, наконец, последняя часть исходного файла класса - объявление его описания.
...
END_METHOD
BEGIN_PROPERTY(...)
...
END_METHOD
Описание класса - это массив структуры GB_DESC
, заполненной специальными макросами, объявленными в gambas.h
GB_DESC MyClassDesc[] =
{
GB_DECLARE("MyClass", sizeof(MyClassStruct)),
...
GB_END_DECLARE
};
Описание класса должно начинаться с GB_DECLARE
макроса и заканчиваться
макросом GB_END_DECLARE
.
Используйте макрос GB_DECLARE
для объявления имени класса и размера его объекта.
Если класс виртуальный, добавьте строку с макросом GB_VIRTUAL_CLASS
. Не
забудьте, что имя класса должно начинаться с точки, а размер объекта
должен быть эквивалентен нулю.
Если класс нормальный, но не создаваемый пользователем, добавьте
строку с макросом GB_NOT_CREATABLE
.
Затем вы добавите строку объявления каждого символа класса.
Ваш класс может наследовать от другого класса, при использовании
макроса
GB_INHERITS
и задании
имени родительского класса.
Класс наследует от родителя все методы, свойства, константы и события.
Более того, структура объекта класса должна включать стуктуру родительского объекта в самом начале. Иначе наследование не будет работать!
Пример:
Класс TreeView наследует от Control.
Структура объекта Control
следующая:
typedef
struct {
GB_BASE ob;
QWidget *widget;
...
}
CWIDGET;
А структура объекта TreeView
следующая:
typedef
struct {
CWIDGET widget;
...
}
CTREEVIEW;
Константа описывается ее именем, ее типом и ее значением.
Для объявления констнаты используйте макрос GB_CONSTANT
.
См. описание макроса, где информации больше.
Свойства описываются их именем, их типом и их функцией реализации.
Для объявления свойства используйте макрос GB_PROPERTY
или макрос
GB_STATIC_PROPERTY
, если свойство статическое.
Если свойство только для чтения, вы должны использовать вместо этого
GB_PROPERTY_READ
или
GB_STATIC_PROPERTY_READ
макрос.
Если вы хотите специальное свойство, которое возвращает тот же
объект, что и виртуальный класс, используйте
GB_PROPERTY_SELF
или
GB_STATIC_PROPERTY_SELF
макрос.
См. описание макроса, где больше иноформации.
Метод описывается его именем, его возвращаемым типом, его сигнатурой и его функцией реализации.
Для объявления метода используйте макрос GB_METHOD
или макрос
GB_STATIC_METHOD
, если метод статический.
См. описание макроса, где больше иноформации.
Событие описывается его именем, его возвращаемым типом и его сигнатурой.
Для объявления события используйте макрос GB_EVENT
. Этот макрос берет
указатель переменной как аргумент, чтобы позволить интерпретатору
разместить идентификатор для этого события. Эта переменная должна быть
объявлена в исходном файле с макросом DECLARE_EVENT
.
См. описание макроса, где больше иноформации.
Для реализации метода вы должны написать функцию, чей код заключен
между двумя макросами: BEGIN_METHOD
и
END_METHOD
.
Макрос BEGIN_METHOD
принимает ДВА аргумента: имя
функции и список аргументов, разделенных точкой с запятой.
Аргументы метода НЕ отделяются запятыми, поскольку они, в действительности, поля стурктуры, передаваемые функции.
Если ваш метод не принимает аргумент, вы должны использовать BEGIN_METHOD_VOID
вместо BEGIN_METHOD
. Макрос BEGIN_METHOD_VOID
принимает только один аргумент - имя функции.
gambas.h
файл включения содержит определения для типов
аргумента:
GB_BOOLEAN
для
булева аргумента. GB_INTEGER
для
целого аргумента. GB_FLOAT
для
аргумента типа
double. GB_STRING
для
строкового аргумента. GB_DATE
для аргумента
типа date (дата). GB_VARIANT
для
аргумента типа
variant (универсальный). GB_OBJECT
для
ссылок на объект. Вы ДОЛЖНЫ использовать эти типы данных!
Для получения параметров у вас есть два макроса : ARG()
и
VARG()
.
Макрос ARG()
возвращает адрес параметра в стеке
интерпретатора и используется с функцией подобной GB.ToZeroString()
или
GB.Store()
.
Макрос VARG()
возвращает значение параметра.
Пример :
BEGIN_METHOD ( TheFunctionName , GB_INTEGER anInteger; GB_STRING aString; GB_VARIANT aVariant; GB_BOOLEAN aBoolean; )Для получения значения параметра вы должны использовать макрос
VARG
.
printf("anInteger = %d\n", VARG(anInteger));Для получения строкового параметра вы должны использовать специальные макросы
STRING
и
LENGTH
, чтобы получить адрес
строки или ее длины.
printf("aString = %*.s\n", LENGTH(aString), STRING(aString));Вы можете также преобразовать строку Gambas в C нуль-завершаемую (zero-terminated) строку с помощью функции
GB.ToZeroString
. Вы
должны использовать макрос ARG
для получения адреса
параметра, а не макрос VARG
, который вернет его
значение.
printf("aString = %.s\n", GB.ToZeroString(ARG(aString)));
GB_VARIANT
- это объединение разных типов данных. Поле
типа этого объединения - этот одна из констант GB_T_* .
if (VARG(aVariant).type == GB_T_STRING)
printf("I got the following string: %s\n", VARG(aVariant)._string.value);
GB_BOOLEAN
- сохраняется как целое, которое равно нулю,
когда FALSE
,
и отличается от нуля, когда TRUE
.
printf("aBoolean = %s\n", VARG(aBoolean) ? "TRUE" : "FALSE");Если вы хотите возбуждать ошибку в вашем методе, вы должны использовать функцию
GB.Error()
для регистрации
ошибки и немедленного возвращения после.
if (VARG(aBoolean))Для возвращения значения из метода вы можете использовать
{
GB.Error("There was an error!");
return;
}
GB.Return()
интерфейсные функции: GB.ReturnInteger()
для возвращения целого,
GB.ReturnBoolean()
для возвращения булева значения и т.д.
GB.ReturnInteger(VARG(anInteger) * 2);
END_METHOD
Для реализации свойства вы должны написать функцию, чей код заключен
между двумя макросами : BEGIN_PROPERTY
и
END_PROPERTY
.
Макрос BEGIN_PROPERTY
принимает одни аргумент: имя
свойства.
Функция вызывается и для чтения, и для записи свойства. Для
различения эти дву случаев вы должны использовать макрос READ_PROPERTY
. Конечно, если
ваше свойство только для чтения, в этом нет нужды.
При чтении свойства вы должны вернуть значение свойства с помощью
одной из
GB.Return
функций.
Написав свойство вы берете значение для записи с помощью макроса VPROP
. Этот макрос принимает один
аргумент: тип данных свойства, который должнен быть одним из Gambas
значений структуры, определенных в gambas.h
:
GB_BOOLEAN
для
булева аргумента. GB_INTEGER
для
целого аргумента. GB_FLOAT
для
аргумента типа
double. GB_STRING
для
строкового аргумента. GB_DATE
для аргумента
типа date. GB_VARIANT
для
аргумента типа
variant. GB_OBJECT
для
объектной ссылки. Используйте макрос PROP
для
получения адреса значения, если вы хотите использовать функции подобные
GB.ToZeroString()
или
GB.Store()
.
Пример:
BEGIN_PROPERTY ( ThePropertyName )Вначале вы должны проверить, хотим ли мы читать или записывать свойство.
if (READ_PROPERTY)Здесь мы читаем свойство...
{
printf("Returning the property value\n");Макрос THIS определен в файле заголовков класса. Он возвращает указатель на данные структуры объекта.
Здесь мы полагаем, что есть char * AStringProperty
, определенное в структуре объекта, что указывает на строку Gambas.
GB.ReturnString(THIS->AStringProperty);Здесь мы записываем свойство...
}
else
{
Для сохранения сложного Gambas типа данных, подобно String
или Object
вы должны использовать
GB.StoreString()
или
GB.StoreObject()
.
Эти функции имеют дело с подсчетом ссылок.
printf("I'm going to write the value: %s\n", GB.ToZeroString(PROP(GB_STRING)));В основном, модифицированное свойство реализует некоторые другие действия...
GB.StoreString(PROP(GB_STRING), &THIS->AStringProperty);
printf("Property has been modified. The new value is %s\n", THIS->AStringProperty);
}
END_PROPERTY