![]() |
![]() |
![]() |
![]() |
Первая часть этой главы обсуждает требования, применимые ко всем классам виджетов:
Этот раздел: | Описывает: |
---|---|
Определение ресурсов | Все аспекты определения ресурсов |
Определение класса виджета | Структура класса виджета и каждое из ее полей |
Методы Класса | Каждый метод класса и как он используется |
Действия виджета | Как сделать ваш виджет интерактивным |
Вы найдете информацию о дополнительных требованиях для создания контейнерных и составных виджетов в конце главы.
Есть два шага в определение ресурсов вашего класса виджета (кроме решения, что они вообще должны быть):
Определите ресурсы, необходимых для класса виджета (то есть ресурсы, которые не существуют в любом из виджетов суперклассов). Это делается в файле заголовка виджета (например в PtButton.h) как ряд выражений #define:
/* * Открытые члены PtButton */ extern PtWidgetClassRef_t *PtButton; #define Pt_BUTTON_ID 6 /* Resources */ #define Pt_ARG_ARM_COLOR Pt_RESOURCE( 6, 0 ) #define Pt_ARG_ARM_IMAGE Pt_RESOURCE( 6, 1 ) #define Pt_ARG_ARM_DATA Pt_ARG_ARM_IMAGE #define Pt_ARG_ARM_FILL Pt_RESOURCE( 6, 2 ) #define Pt_ARG_SET_FILL Pt_ARG_ARM_FILL /* * Частные члены PtButton */ /* Widget structure */ typedef struct Pt_button_widget { PtLabelWidget_t label; PgColor_t arm_color; PhImage_t *arm_data; PhImage_t *unarmed_data; uchar_t arm_fill; PtCallbackList_t *activate; } PtButtonWidget_t;
Все имена и номера деклараций ресурсов должны быть уникальны. В вышеупомянутом примере, Pt_ARG_ARM_COLOR представляет уникальное имя декларации ресурса, Pt_RESOURCE( 6, 0 ) представляет уникальный номер ресурса, и сам ресурс имеет соответствующее вхождение в структуре образца виджета с именем arm_color.
Когда Вы создаете новый виджет, то для этого должны выбрать уникальный номер виджета. Файл заголовка PtT.h содержит два макроса, чтобы помочь Вам сделать это:
Pt_RESOURCE( номер_виджета, номер_ресурса) Pt_USER( номер_виджета )
![]() |
Pt_USER() макрос предназначен для виджетов, создаваемых только для внутреннего использования. Если Вы намереваетесь распространять виджеты, которые создали, в виде общедоступной или коммерческой библиотеки, пожалуйста войдите в контакт с QSSL Обуслуживание Заказчика. Они дадут Вам уникальный диапазон номеров виджетов и присвоят вашему виджету префикс. Это предотвратит вашу библиотеку виджетов от конфликта с другими коммерческими библиотеками виджетов от третьего лица. |
В вашем первом внутреннем виджете используйте:
#define MY_1ST_WIDGET_RESOURCE1 Pt_RESOURCE( Pt_USER( 1 ), 0 ); #define MY_1ST_WIDGET_RESOURCE2 Pt_RESOURCE( Pt_USER( 1 ), 1 );
В вашем втором внутреннем виджете используйте:
#define MY_2ND_WIDGET_RESOURCE1 Pt_RESOURCE( Pt_USER( 2 ), 0 ); #define MY_2ND_WIDGET_RESOURCE2 Pt_RESOURCE( Pt_USER( 2 ), 1 );
Макрос Pt_USER( 1 ) определяет номер виджета, который позволяет до 1000 ресурсов: он определяет номер виджета 5,001,000. Макрос Pt_USER( 2 ) определяет номер 5,002,000, и так далее.
Вторая часть макроса Pt_RESOURCE() определяет номер ресурса: Pt_RESOURCE( Pt_USER( 2 ), 5 ) определяет номер ресурса 5,002,005. Виджет, определенный как Pt_USER( 2 ) может определять уникальные номера ресурсов от 5,002,000 до 5,002,999.
Записи ресурсов используются, чтобы подключить декларации ресурсов, описанные выше, к членами структуры виджета. Записи ресурсов определены как таблица в файле исходного кода и переданы как параметр, когда Вы сначала создаете класс виджета.
Это таблица элементов PtResourceRec_t. Эта структура объявлена следующим образом:
typedef struct Pt_resource_rec { unsigned long type; void (*mod_f)( PtWidget_t *, PtArg_t const * ); int (*query_f)( PtWidget_t const *, PtArg_t * ); unsigned long arg_value; unsigned long arg_len; } PtResourceRec_t;
Значение (декларация), с которой эта запись связана через член образца виджета. Например, Pt_ARG_FLAGS.
Функция, которая вызывается, когда этот ресурс устанавливается пользователем. Этот член распознает несколько специальных удобных значений кроме адреса функции. Специальные значения включают:
Функция, вызываемая, когда этот ресурс запрошен через PtGetResources(). Если никакая функция не обеспечивается (то есть query_f равно NULL), ресурс сообщается нормальным способом (смотрите PtSetArg() и PtGetResources() в Справочном Руководстве по Библиотеке (Library Reference)) Фотона.
Специальные значения члена query_f включают:
Это битовые поля, которые устанавливают члены структуры виджета. Член arg_value используется для всех ресурсов; arg_len используется, чтобы установить второй член структуры виджета. Для массива, arg_len имеет тип и смещение счетчика массива. Для Булевого значения, arg_len это битовая маска. Если ресурс не массив или Булевый тип, arg_len обычно 0.
Данные, закодированные в этих полях, включают:
Следующие макросы делают использование arg_value и arg_len более удобным:
Следующие разделы описывают значения членов arg_value и arg_len для каждого типа ресурса. Для большинства ресурсов, arg_len не используется; если не упомянуто иначе ниже, установите его в 0.
![]() |
Память для некоторых из ресурсов (указанных ниже) распределяется и освобождается как необходимо. Если Вы имеете метод Разрушения, то не должны освобождать память для этих ресурсов. Если Вы освобождаете любую память, то должны устанавливать освобожденные указатели в NULL или могут произойти неожиданные результаты. |
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_NUMBER(wgt, member1) | char, short, или long (signed или unsigned) |
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_FLAGS(wgt, member1) | char, short, или long (предпочтительно unsigned) |
Для Флаговых ресурсов, "маска" не часть ресурса -- это только путь сказать API установки ресурсов, которые биты приложение хочет сохранить.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_STRING(wgt, member1) | char * |
Этот ресурс распределяется, основываясь на значении, возвращенном strlen(); смотрите примечание выше.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_STRUCT(wgt, member1) | Любой тип |
Это члены виджета, которые имеют установленный размер. При установке таких ресурсов, Вы передаете указатель на значение, и значение копируется в структуру виджета. Этот тип полезен для структур, также как для других типов данных, которые не вписываются в long (такие как float или double).
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_POINTER(wgt, member1) | Любой тип указателя, включая void * |
Виджет делает поверхностную копию значения указателя.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_ALLOC(wgt, member1) | Любой тип указателя, включая void * |
Место распределяется для ресурса с размером, указанным приложением; смотрите примечание выше.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_LINK(wgt, member1) | Указатель на структуру |
Структура должна начаться со "следующего" указателя. Место распределяется для ресурса; смотрите примечание выше.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_CALLBACK_LIST(wgt, member1) | Указатель на структуру |
Структура должна начаться со "следующего" указателя. Место распределено для ресурса; смотрите примечание выше.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_BOOLEAN(wgt, member1) | char, short, int или long (предпочтительно unsigned) |
arg_len это битовая маска. Она не сохраняется где-нибудь в виджете -- это только константа, которая определяет, в котором бите структуры виджета ресурс сохранен.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_ARRAY(wgt, member1) | Указатель на некоторый тип |
Этот тип ресурса также использует arg_len:
arg_len | C тип member2 |
---|---|
Pt_ARG_IS_NUMBER(wgt, member2) | char, short или long |
Размер каждого элемента массива это размер типа, указанного member1. Место распределяется для ресурса; смотрите примечание выше.
arg_value | C тип member1 |
---|---|
Pt_ARG_IS_IMAGE(wgt, member2) | PhImage_t * |
Место распределяется для ресурса; смотрите примечание выше. Для получения дополнительной информации о структуре PhImage_t, смотрите Справочное Руководство по Библиотеке (Library Reference) Фотона.
Теперь давайте посмотрим на некоторые типовые объявления ресурсов. Сначала давайте взглянем назад на наш первоначальном примере виджета, ShadowedBox. Он определяет два ресурса в файле заголовка:
/* ресурсы виджета */ #define SBW_SHADOW_COLOR Pt_RESOURCE( Pt_USER( 0 ), 0 ) #define SBW_SHADOW_OFFSET Pt_RESOURCE( Pt_USER( 0 ), 1 ) /* widget instance structure */ typedef struct shadowed_box_widget{ PtBasicWidget_t basic; PgColor_t shadow_color; short shadow_offset; } ShadowedBoxWidget;
Файл исходного кода определяет таблицу ресурсов, которая подключает ресурсы к классу виджета:
static PtResourceRec_t resources[] = { SBW_SHADOW_COLOR, Pt_CHANGE_REDRAW, 0, Pt_ARG_IS_NUMBER( ShadowedBoxWidget, shadow_color ), 0, SBW_SHADOW_OFFSET, Pt_CHANGE_RESIZE_REDRAW, 0, Pt_ARG_IS_NUMBER( ShadowedBoxWidget, shadow_offset ), 0, };
Давайте исследуем первый ресурс в таблице более подробно:
Теперь давайте посмотрим на более детальный пример. В файле заголовка виджета мы имеем:
/* ресурсы виджета */ #define MW_ARG_MY_CHARACTER Pt_RESOURCE( Pt_USER(1), 0 ) #define MW_ARG_MY_STRING Pt_RESOURCE( Pt_USER(1), 1 ) #define MW_ARG_MY_SHORT Pt_RESOURCE( Pt_USER(1), 2 ) #define MW_ARG_MY_FLAGS Pt_RESOURCE( Pt_USER(1), 3 ) #define MW_ARG_MY_FLAG_BIT Pt_RESOURCE( Pt_USER(1), 4 ) #define MW_ARG_MY_POINT_ARRAY Pt_RESOURCE( Pt_USER(1), 5 ) #define MW_ARG_MY_TAG_DATA Pt_RESOURCE( Pt_USER(1), 6 ) #define MW_CB_MY_CALLBACK Pt_RESOURCE( Pt_USER(1), 7 ) #define MW_MY_FLAG_BIT 0x04000000 /* структура образца виджета */ typedef struct my_widget{ PtBasicWidget_t basic; //Подкласс PtBasic. char character; char *my_string; short my_short; long flags; PhPoint_t *points; //Массив указателей. ushort_t num_points; void *tag_data; PtCallbackList_t *my_callbacks; //Список ссылок обратных вызовов. } MyWidget_t;
В функции создания класса в файле исходного кода мы имеем:
static const PtResourceRec_t resources = { Pt_ARG_POS, arg_pos_override, 0, Pt_ARG_IS_NUMBER( PtWidget_t, area.pos ), 0, MW_ARG_MY_CHARACTER, Pt_CHANGE_REDRAW, 0, Pt_ARG_IS_NUMBER( MyWidget_t, character ), 0, MW_ARG_MY_STRING, Pt_CHANGE_RESIZE_REDRAW, 0, Pt_ARG_IS_STRING( MyWidget_t, my_string ), 0, MW_ARG_MY_SHORT, set_my_short, get_my_short, 0, 0, MW_ARG_MY_FLAGS, Pt_CHANGE_INVISIBLE, 0, Pt_ARG_IS_FLAGS( MyWidget_t, flags ), 0, MW_ARG_MY_FLAG_BIT, Pt_CHANGE_INVISIBLE, 0, Pt_ARG_IS_BOOLEAN ( MyWidget_t, flags ), MW_MY_FLAG_BIT, MW_ARG_MY_POINT_ARRAY, Pt_CHANGE_RESIZE_REDRAW, 0, Pt_ARG_IS_ARRAY( MyWidget_t, points ), Pt_ARG_IS_NUMBER( MyWidget_t, num_points ), MW_ARG_MY_TAG_DATA, Pt_CHANGE_INVISIBLE, 0, Pt_ARG_IS_ALLOC( MyWidget_t, tag_data ), 0, MW_CB_MY_CALLBACK, Pt_CHANGE_INVISIBLE, 0, Pt_ARG_IS_CALLBACK_LIST( MyWidget_t, my_callback ), 0, }
Pt_ARG_POS наследован от PtWidget. Здесь мы переназначаем его функцию mod_f() одной из его собственных.
Ресурс MW_ARG_MY_SHORT и функции mod_f()/query_f() могут выглядеть следующим образом:
static void set_my_short( PtWidget_t *widget, PtArg_t *argt ) { MyWidget_t *mw = (MyWidget_t *)widget; if( mw->my_short == (short)argt->value ) return; // не делать работу, если ничего не изменилось. mw->my_short = argt->value; // Мой виджет должен перерисовываться, когда my_short изменяется ... PtDamageWidget( widget ); } static int get_my_short( PtWidget_t *widget, PtArg_t *argt ) { MyWidget_t *mw = (MyWidget_t *)widget; if( argt->value ) // Адрес указателя на short находится в argt->value *(short **)argt->value = &mw->my_short; else argt->value = (long) mw->my_short; return Pt_TRUE; /* Единственный случай, когда можно было бы возвратить Pt_FALSE, это если никакие данные не даются в результате запроса */ }
Для большего количества примеров ресурсов и функций mod_f()/query_f(), смотрите /qnx4/phtk/src/widgets и каталог /qnx4/phtk/src/contrib, которые содержат много примеров и шаблонов виджетов.
В Фотоне, класс виджета определяется много подобно виджету. Вы устанавливаете список параметров или ресурсов класса и вызываете PtCreateWidgetClass(). Этот список используется, чтобы установить члены поля структуры класса виджета, которую Фотон использует, чтобы определить, как обработать виджет.
Давайте посмотрим на общую форму структуры PtWidgetClass_t:
struct Pt_widget_class { char *description; struct Pt_widget_class *superclass; PtWidgetClassRef_t *class_ref; unsigned class_len; unsigned state_len; unsigned long flags; void (*dflts_f)( PtWidget_t * ); int (*init_f)( PtWidget_t * ); int (*connect_f)( PtWidget_t * ); void (*unrealize_f)( PtWidget_t * ); void (*destroy_f)( PtWidget_t * ); PtResourceRec_t *resources; void (*realized_f)( PtWidget_t * ); PtRawCallbackList_t *callbacks; PhSoul_t widget_souls; int (*setres_f)( PtWidget_t *, int, PtArg_t const *, PtResourceRec_t const *rrec ); int (*getres_f)( PtWidget_t const *, int, PtArg_t * ); short version; unsigned short num_resources; unsigned int wd_state_len; unsigned int ex_state_len; PtDataHdr_t *class_data; void *ex_data; void (*or_dflts_f)( PtWidget_t * ); void (*or_destroy_f)( PtWidget_t * ); void (*syncwidget_f)( PtWidget_t *widget ); int (*calc_region_f)( PtWidget_t *, unsigned int *, PhRegion_t *, PhRect_t * ); PtResourceRec_t *overridden_resources; ushort_t num_overridden_resources; uchar_t num_actions,padding; void (*resource_changed_f)( PtWidget_t *, long ); PtWidgetAction_t *actions; void (*calc_border_f)( PtWidget_t const *, PhRect_t * ); int max_style_index; PtWidgetClassStyle_t **styles; }; typedef struct Pt_widget_class PtWidgetClass_t;
Давайте посмотрим на структуру PtWidgetClass_t член за членом:
Это удобно для разрешения общим ресурсам типа Pt_ARG_COLOR перейти к порожденным дочерним виджетам без необходимости писать функцию переадресации ресурса.
Не все члены структуры класса виджета могут быть установлены непосредственно; некоторые используются внутренне библиотекой виджетов. Члены, которые Вы можете изменять, используя декларации ресурсов класса, следующие:
Член | Описание | Декларация ресурса |
---|---|---|
state_len | Длина образца | Pt_SET_STATE_LEN |
flags | Флаги | Pt_SET_FLAGS |
dflts_f | Метод По Умолчанию | Pt_SET_DFLTS_F |
init_f | Метод Инициализации | Pt_SET_INIT_F |
extent_f | Метод Размерности | Pt_SET_EXTENT_F |
connect_f | Метод Подключения | Pt_SET_CONNECT_F |
draw_f | Метод Рисования | Pt_SET_DRAW_F |
unrealized_f | Метод Дереализации | Pt_SET_UNREALIZE_F |
realized_f | Метод Реализации | Pt_SET_REALIZED_F |
destroy_f | Метод Разрушения | Pt_SET_DESTROY_F |
resources | Таблица ресурсов | Pt_SET_RESOURCES |
num_resources | Число ресурсов | Pt_SET_NUM_RESOURCES |
callbacks | Необработанные обратные вызовы | Pt_SET_RAW_CALLBACKS |
setres_f | Метод Установки Ресурсов | Pt_SET_SETRESOURCES_F |
getres_f | Метод Получения Ресурсов | Pt_SET_GETRESOURCES_F |
version | Номер версии | Pt_SET_VERSION |
description | Текстовое описание класса; смотрите ниже. | Pt_SET_DESCRIPTION |
Для описания Вы могли бы включить в ваше определение класса кое-что подобно этому:
static const PtArg_t args[] = { ... { Pt_SET_DESCRIPTION, (long) "PtButton" }, ... };
В общих чертах, принимается, что описание соответствует имени виджета (то есть приложения могли бы очевидно использовать это поле, чтобы отобразить имя класса виджета) и следовательно рекомендуется, чтобы Вы следовали этой практики. Если требуется дополнительная информация, принятое соглашение состоит в том, чтобы добавить в конец точку с запятой (:) сопровождаемую текстом; приложения, которые используют это поле описания будут искать первый : и основывать на этом синтаксический анализ.
Так что изменим вышеупомянутый пример
{ Pt_SET_DESCRIPTION, (long) "PtButton:дейв был здесь" },
![]() |
Это соглашение, не правило. Вы можете использовать это поле для чего хотите, пока Вы понимаете, что некоторые приложения могут использовать это поле (только для информационных целей). Наиболее изящный способ, чтобы такие приложения игнорировали все, что идет после точки с запятой, подобно этому:
{ Pt_SET_DESCRIPTION, (long) ":дейв был здесь" }, в этом случае приложение должно указать состояние "значение не известно" (то есть игнорировать все после :). |
При определении заказного класса виджета Вы можете расширять определение его суперкласса новыми методами "уровня класса" и/или обратными вызовами. Например, класс PtWidget расширяет PtBasic, который добавляет новые методы класса для обеспечения уведомления фокуса. Это было сделано как показано в следующей выборке из заголовочного файла PtBasic.h:
typedef struct Pt_basic_widget_class { PtWidgetClass_t core; void (*got_focus_f)( PtWidget_t *, PhEvent_t * ); void (*lost_focus_f)( PtWidget_t *, PhEvent_t * ); void (*calc_opaque_f)( PtWidget_t * ); } PtBasicWidgetClass_t; #define Pt_SET_GOT_FOCUS_F (Pt_ARG_IS_POINTER(PtBasicWidgetClass_t,got_focus_f)) #define Pt_SET_LOST_FOCUS_F (Pt_ARG_IS_POINTER(PtBasicWidgetClass_t,lost_focus_f)) #define Pt_SET_CALC_OPAQUE_F (Pt_ARG_IS_POINTER(PtBasicWidgetClass_t,calc_opaque_f))
Когда определение класса расширено таким образом, новый размер структуры класса должен быть передан как второй параметр для PtCreateWidgetClass():
PtBasic->wclass = PtCreateWidgetClass( PtWidget, sizeof(PtBasicWidgetClass_t ),... );
Если класс не расширен, второй параметр может быть передан как 0. Также, когда класс расширен, Вы должны определить новые декларации Pt_SET*, чтобы обеспечить доступ к новым элементам класса из функции создания класса.
Класс виджета PtBasic обеспечивает следующие три дополнительных члена структуры:
Член | Описание | Декларация ресурса |
---|---|---|
got_focus_f | Метод Получения Фокуса | Pt_SET_GOT_FOCUS_F |
lost_focus_f | Метод Потери Фокуса | Pt_SET_LOST_FOCUS_F |
calc_opaque_f | Метод Расчета Непрозрачного Прямоугольника | Pt_SET_CALC_OPAQUE_F |
Давайте посмотрим на таблицу ресурсов класса из нашего примера ShadowedBox более подробно:
static PtArg_t args[] = { { Pt_SET_VERSION, 110}, { Pt_SET_STATE_LEN, sizeof( ShadowedBoxWidget ) }, { Pt_SET_DFLTS_F, (long)shadowedbox_dflts }, { Pt_SET_DRAW_F, (long)shadowedbox_draw }, { Pt_SET_FLAGS, 0, Pt_RECTANGULAR }, { Pt_SET_NUM_RESOURCES, sizeof( resources ) / sizeof( resources[0] ) }, { Pt_SET_RESOURCES, (long)resources, sizeof( resources ) / sizeof( resources[0] ) }, };
Этот раздел описывает роль и обязанности методов класса, определенных в структуре класса виджета. Фундаментальные методы, определенные PtWidget, следующие:
Виджет PtBasic расширяет их тремя дополнительными методами:
Эти методы Вы пишете, чтобы определить функциональные возможности вашего виджета. Не все методы должны быть определены и кодированы классом виджета; они могут быть унаследованы от суперкласса. Почти все виджеты нуждаются по крайней мере в метод Рисования, начиная с основной цели создания заказного виджета состоящей в том, чтобы что нибудь рисовать.
Тип: Подключен вниз, неостанавливаемый
Этот метод устанавливает значения по умолчанию для всех членов структуры образца виджета. Он вызывается в течение создания образца виджета (запрос к PtCreateWidget()). Когда образец виджета создается, все члены структуры образца заполняются нулями и затем вызывается метод По Умолчанию для каждого родительского класса (начиная с PtWidget сверху) в последовательности сверху донизу. Это позволяет классам низшего уровня переназначать значения по умолчанию, установленные родительскими классами в иерархии. Вот пример, показывающий как инициализирует переменные PtBasic:
static void basic_dflts( PtWidget_t *widget ) { PtBasicWidget_t *basic = (PtBasicWidget_t *) widget; widget->border_width = 2; widget->cursor_color = Ph_CURSOR_DEFAULT_COLOR; widget->resize_flags |= Pt_RESIZE_XY_AS_REQUIRED; basic->color = Pg_BLACK; basic->fill_color = Pg_GREY; basic->top_border_color = Pg_WHITE; basic->bot_border_color = Pg_DGREY; basic->flags = Pt_DAMAGE_ON_FOCUS; }
Хотя переменные образца в этом примере определенные для PtBasic, методика инициализации общая для всех методов По Умолчанию.
Тип: Подключен вверх, останавливаемый
Этот метод впервые вызвается, когда виджет реализуется (запрос к PtRealizeWidget()). Метод Инициализации делает заключительные проверки, чтобы гарантировать, что виджет "extentable". Эта проверка гарантирует, что все члены, используемые в последующем методе Размерности, правильно назначены.
Метод Инициализации также лучшее место, чтобы создать неэкспортируемые зависимые виджеты. Неэкспортируемые зависимые виджеты используются виджетом, но не доступны пользователю. Например, виджет типа PtPrintSel использует другие виджеты (PtText, PtLabel и PtButton), но не позволяет пользователю взаимодействовать непосредственно с зависимыми виджетами. Вместо этого, виджет обеспечивает новые уникальные ресурсы, используемые внутренне, чтобы установить зависимые виджеты. Для получения дополнительной информации о экспортируемых зависимых виджетах, смотрите "Анатомию составного виджета" позже в этой главе.
Инициализация выполняется каждый раз, когда виджет реализован. Метод Инициализации вызывается сначала для этого виджета, затем для его родительского суперкласса и так далее до основного класса виджета (PtWidget). Любой класс виджета в цепочке может прервать последовательный процесс, возвращая Pt_END.
Вот пример, показывающий как реализуется виджет PtContainer:
static in PtContainerInit( PtWidget_t *widget ) { PtContainerRegister( widget ); return( Pt_CONTINUE ); }
Метод Инициализации также используется, чтобы регистрировать виджеты для обработки всплывающих подсказок. Все контейнерные виджеты обеспечивают заданный по умолчанию механизм обработки всплывающих подсказок. Если Вы хотите, чтобы ваш виджет поддержал всплывающие подсказки, то должны регистрировать виджет с контейнером в этой функции. Вот выборка из кода PtLabel:
static int label_init( PtWidget_t *widget ) { PtLabelWidget_t *label = (PtLabelWidget_t *) widget; PtBalloonCallback_t bcalls; PtArg_t argt; if( (label->flags & Pt_SHOW_BALLOON) && ( !( label->flags & Pt_BALLOON_REGISTERED ) ) ) { bcalls.widget = widget; bcalls.event_f = label_balloon_callback; PtSetArg( &argt, Pt_CB_BALLOONS, &bcalls, 0 ); PtSetResources( widget->parent, 1, &argt ); label->flags |= Pt_BALLOON_REGISTERED; } return Pt_CONTINUE; }
Тип: Наследуемый
Это второй метод, вызываемый в течение реализации виджета (запрос к PtRealizeWidget()). Метод Размерности ответствен за определение экранной недвижимости виджета (ограничивающий блок) в отношении его политики изменения размеров. Метод Размерности вызывается часто в течение жизни виджета -- всякий раз, когда виджет перемещен или изменены его размеры, или изменяются ресурсы помеченные как Pt_CHANGE_RESIZE или Pt_CHANGE_RESIZE_REDRAW.
Следующее это примеры этих типов ресурсов, как определено классом PtWidget:
static PtResourceRec_t resources[] = { { Pt_ARG_AREA, Pt_CHANGE_RESIZE, 0, Pt_ARG_IS_STRUCT(PtWidget_t, area) }, { Pt_ARG_POS, Pt_CHANGE_RESIZE, 0, Pt_ARG_IS_STRUCT(PtWidget_t, area.pos) }, { Pt_ARG_DIM, Pt_CHANGE_RESIZE, 0, Pt_ARG_IS_STRUCT(PtWidget_t, area.size) }, };
Кроме того, метод Размерности вызывается всякий раз, когда любой другой ресурс заставляет виджет изменять размер или позицию. Следующий примера кода взят из PtLabel:
static PtResourceRec_t resources[] = { { Pt_ARG_LABEL_TYPE, Pt_CHANGE_RESIZE_REDRAW, 0, Pt_ARG_IS_NUMBER(PtLabelWidget_t, type), 0 }, };
Двигатель виджета использует размерности, расчитанные в этом методе, чтобы определить, когда этот виджет вовлечен в событие, когда виджет должен быть восстановлен, и какие другие виджеты должны быть восстановлены, когда этот изменяется.
Каждый класс виджета наследует метод Размерности от его суперкласса. Если этот метод подходящий, Вы не будете должны обеспечить ваш собственный метод Размерности. Если метод Размерности суперкласса не соответствует потребностям вашего виджета, Вы должны обеспечить только то, что суперкласс виджета не обеспечивает, затем вызывать метод Размерности суперкласса, чтобы сделать остальную часть работы.
Необычно писать метод Размерности, который вычисляет полную размерность без использования метода суперкласса. Довольно часто Вы будете хотеть поведение размерности суперкласса не в полной мере. Есть обычный способ предотвратить метод Размерности суперкласса от выполнения любого набора поведений размерности (смотрите раздел "Метод Размерности" главы Использование Суперклассов Виджетов для подробностей).
Размерность виджета обычно включает четыре этапа:
Если холст виджета не может быть изменен в размере, чтобы охватить прямоугольник исполнения, PtResizeCanvas() устанавливает Pt_UCLIP бит во флагах изменения размера виджета. Метод Рисования виджета должен проверить бит Pt_UCLIP. Если этот бит установлен, метод Рисования должен применить отсечение, чтобы предотвратить виджет от исполнения вне его холста.
PtSuperClassExtent( PtBasic, widget)
чтобы выполнить окончательное вычисление размерности. Метод Размерности PtBasic'а использует позицию, измерение, ширину рамки и флаги виджета, чтобы определить размерности.
Вот пример, который показывает как применять эти рекомендации:
mywidget_extent( PtWidget_t *widget ) { MyWidgetUnion_t *mwu = (MyWidgetUnion_t *)widget; PhRect_t canvas, render; PhDim_t size; PtCalcCanvas( widget, &canvas ); render.ul = render.lr = canvas.ul; PgExtentText( &render, &render.ul, mwu->label.font, mwu->label.string, 0 ); size.x = render.lr.x - render.ul.x + 1; size.y = render.lr.y - render.ul.y + 1; PtResizeCanvas( widget, &size ); PtSuperClassExtent( PtBasic, widget ); }
Тип: Подключенный вверх, останавливаемый
Это третий метод, вызваемый в течение реализации виджета (запрос к PtRealizeWidget()). Метод Подключения создает любые требуемые области Фотона. Обычно, нет необходимости явно создавать вашу собственную область пока метод Подключения PtWidget'а делает это для Вас.
Однако, может быть выгодно создать вашу собственную область, если Вы должны изменять область, основываясь на текущей среде. Например, виджет PtMenu должен изменять область всякий раз, когда он отображается:
static int menu_connect( PtWidget_t *widget ) { PhRegion_t region; unsigned fields; PhRect_t rect; PtMenuWidget_t *menu = (PtMenuWidget_t *)widget; PtWidget_t *wp; /* вычисление области меню */ fields = UINT_MAX; if( !PtCalcRegion( &fields, widget, ®ion, &rect ) ) return( -1 ); /* открытие области меню */ region.parent = menu->ff_wgt->rid; region.events_opaque |= Ph_EV_DRAW | Ph_EV_PTR_ALL; region.events_opaque &= ~Ph_EV_KEY; region.events_sense |= Ph_EV_PTR_ALL; region.events_sense &= ~Ph_EV_KEY; region.flags = 0; fields |= Ph_REGION_PARENT | Ph_REGION_EV_SENSE | Ph_REGION_EV_OPAQUE; fields &= ~( Ph_REGION_BEHIND | Ph_REGION_IN_FRONT ); widget->rid = PhRegionOpen( fields, ®ion, &rect, NULL ); wp = widget; while( PtWidgetIsClass( wp, PtMenu ) ) { menu_pdr_start( wp ); if ( !wp->parent ) break; wp = wp->parent->parent; } if( widget->parent && PtWidgetIsClassMember( widget->parent, PtContainer ) ) { if( !( menu->flags & Pt_MENU_CHILD ) ) { // Если меню от окна, дать фокус этому окну. PhEvent_t event; memset( &event, 0, sizeof( event ) ); menu->prev_focus = PtContainerFindFocus( widget->parent ); if( widget->parent->class_rec->flags & Pt_DISJOINT ) PtContainerNullFocus( widget->parent, &event ); else { int flags = widget->parent->flags; widget->parent->flags |= Pt_GETS_FOCUS; PtContainerGiveFocus( widget->parent, &event ); widget->parent->flags = flags; } } else menu->flags |= Pt_MENU_SUBFOCUS; ((PtContainerWidget_t *)widget->parent)->focus = widget; } wp = PtFindDisjoint( widget ); for( wp = wp->parent; wp && (PtWidgetIsClassMember(wp, PtMenu) || PtWidgetIsClassMember(wp, PtMenuButton)); wp = wp->parent); if( wp ) { wp = PtFindDisjoint( wp ); if (PtWidgetIsClassMember( wp, PtWindow )) ((PtContainerWidget_t *)wp)->last_focus = NULL; if( !( PtWindowGetState( wp ) & Ph_WM_STATE_ISFOCUS ) ) { PtWindowFocus( wp ); } } } /* остановить инициализацию */ return( Pt_END ); }
Если Вы создаете вашу собственную область, метод Подключения PtWidget'а не будет создавать другую область - он изменяет текущую область. Чтобы предотвратить модификацию текущей области, которую имеет класс виджета, возвратите Pt_END.
Тип: Наследуемый
Этот метод вызывается после того, как виджет был реализован. Его функция подобна обратному вызову Pt_CB_REALIZED, но в отличие от обратного вызова Pt_CB_REALIZED, к нему не может обратиться разработчик, использующий ваш виджет.
Этот метод используется прежде всего составными виджетами, чтобы выполнить любую пострелизную операцию, типа реализации любых зависимых виджетов, которые не могли быть реализованы к этому моменту. Это последний метод, который вызывается до метода Рисования, и он вызывается до обратных вызовов Pt_CB_REALIZED. Для получения дополнительной информации, смотрите раздел "Анатомия составного виджета."
Тип: Наследуемый
Это последний метод, вызваесый в течение процесса реализации. Метод Рисования используется, чтобы выполнить виджет на экране в течение реализации и вызывается, чтобы перерисовать виджет впоследствии всякий раз, когда он поврежден.
Когда виджет поврежден, указатель на поврежденный виджет и список неперекрывающих расположений, описывающих повреждение, передаются методу Рисования. Первое неперекрывающее расположение в списке повреждения показывает полные размерности повреждения (его блок ограничения охватывает все оставшиеся неперекрывающие расположения). Оставшиеся неперекрывающие расположения содержат фактические размерности поврежденные. Если виджет не сложен или передает много данных рисования (большие изображения) и может быть ускорен, рисуя только поврежденные области, Вы должны игнорировать список повреждения.
Библиотека виджетов использует список повреждения, чтобы отсечь части, которые не должны рисоваться. Если Вы планируете использовать неперекрывающиеся расположения повреждения, удостоверитесь, что переводите холст виджета, используя смещение виджета. Используйте PtWidgetOffset(), чтобы получить смещение - список повреждения относительно непересекающегося родительского виджета (обычно виджета PtWindow).
Метод рисования ограничивает свои модификации холстом поврежденного виджета. Это делается установкой прямоугольника отсечения если нобходимо. Вот пример рисования, взятый из кода для PtButton:
static void button_draw( PtWidget_t *widget, PhTile_t *damage ) { PtButtonWidget_t *button = (PtButtonWidget_t *)widget; PgColor_t tcolor; button->label.data = button->unarmed_data; /* установим fill_color в arm_color если требуется */ if ( widget->flags & Pt_SET ) { if( button->arm_fill == 1 ) { tcolor = button->label.basic.fill_color; button->label.basic.fill_color = button->arm_color; } if( button->arm_data ) button->label.data = button->arm_data; } /* рисуем кнопку - включаем подсветку */ PtSuperClassDraw( PtLabel, widget, damage ); /* восстанавливаем fill_color */ if ( widget->flags & Pt_SET ) { if ( button->arm_fill == 1 ) button->label.basic.fill_color = tcolor; } }
Следующая выборка кода (из PtArc) показывает, как устанавливать бит Pt_UCLIP во флагах изменения размера виджета воздействуя на отсечение:
PtCalcCanvas( widget, &rect ); if ( widget->resize_flags & Pt_UCLIP ) PtClipAdd( widget, &rect ); PgDrawArc( &pos, &dim, start, end, arc->type | flags ); if ( widget->resize_flags & Pt_UCLIP ) PtClipRemove( );
Вы будете использовать функции Pg* в методе Рисования вашего виджета, но Вы должны использовать их безопасно. Вот некоторые моменты, которые необходимо помнить:
Для получения дополнительной информации об этих функциях, смотрите Справочное Руководство по Библиотеке (Library Reference) Фотона.
Тип: Подключен вверх
Этот метод вызывается, когда виджет дереализуется. Метод Дереализации ответствен за удаление любых областей, созданных виджетом (widget->rid удаляется автоматически методом Дереализации класса PtWidget). Метод Дереализации должен освободить любую память, которая была перераспределена в течение процесса реализации.
Метод Дереализации также используется, чтобы дерегистрировать виджеты. Например, если виджет метки зарегистрировал всплывающую подсказку в своем методе Инициализации, он должен дерегистрировать ее в методе Дереализации, или всплывающая подсказка будет выскакивать всякий раз, когда указатель останавливается на последнем месте расположения виджета. Вот пример, взятый из кода для PtLabel:
static int label_unrealize(PtWidget_t *widget ) { PtLabelWidget_t *label = (PtLabelWidget_t*)widget; PtBalloonCallback_t bcalls; PtArg_t arg; if(label->balloon_widget) PtDestroyWidget( label->balloon_widget ); bcalls.widget = widget; bcalls.event_f = label_balloon_callback; if( label->flags & Pt_SHOW_BALLOON ){ PtSetArg( &arg, Pt_CB_BALLOONS, &bcalls, Pt_LINK_DELETE ); PtSetResources( widget->parent, 1, &arg ); } label->flags &= ~Pt_BALLOON_REGISTERED; return Pt_CONTINUE; }
Тип: Подключен вверх, неостанавливаемый
Этот метод вызывается, когда виджет разрушается приложением. Метод Разрушения ответствен за освобождение всех ресурсов, распределенных классом виджета в течение его срока службы. Метод Разрушения не имеет дело с памятью, распределенной суперклассом виджета, потому что каждый класс ответствен за освобождение своей собственной памяти. Вот пример, взятый из кода для PtLabel:
static int label_destroy( PtWidget_t *widget ) { PtLabelWidget_t *label = (PtLabelWidget_t *)widget; PtArg_t arg; PtBalloonCallback_t bcalls; if( label->flags & Pt_BALLOON_REGISTERED ) { bcalls.widget = widget; bcalls.event_f = (void*)label_balloon_callback; if( label->flags & Pt_SHOW_BALLOON ) { PtSetArg( &arg, Pt_CB_BALLOONS, &bcalls, Pt_LINK_DELETE ); PtSetResources( widget->parent, 1, &arg ); } label->flags &= ~Pt_BALLOON_REGISTERED; } return 0; }
Тип: Наследуемый
Этот метод используется, чтобы установить стандартный процесс установки ресурса, встроенный в библиотеку Фотона. Составные виджеты это единственные виджеты, которые устанавливают этот метод (смотрите раздел "Анатомия составного виджета").
Тип: Наследуемый
Этот метод используется, чтобы установить стандартный процесс поиска ресурса, встроенный в библиотеку Фотона. Составные виджеты это единственные виджеты, которые устанавливают этот метод (смотрите раздел "Анатомия составного виджета").
Тип: Наследуемый
Этот метод используется только подклассами PtBasic'а. Он вызывается, когда виджет получает фокус. Если ваш виджет получает фокус таким образом, что весь нуждается в перерисовке, очистите флаг Pt_DAMAGE_ON_FOCUS (от PtBasic) и повредите соответствующую область, когда ваш виджет получит фокус.
Этот метод не подключен. Если ваш класс определяет метод Получения Фокуса, вы будете должны или вызвать PtSuperClassLostFocus(), чтобы сохранить автоматическое подсвечивание и поведение метода Получения Фокуса уровня виджета или реализовать поведение в методе Получения Фокуса вашего класса. Вот выборка из кода для PtBasic:
static basic_got_focus( PtWidget_t *widget, PhEvent_t *event) { PtBasicWidget_t *basic =( PtBasicWidget_t *) widget; PtCallbackInfo_t cbinfo; PtArg_t arg; /* повредим виджет так, чтобы исполнение фокуса вступило в силу */ if( ( widget->flags & Pt_FOCUS_RENDER ) && ( basic->flags & Pt_DAMAGE_ON_FOCUS ) ) PtDamageWidget( widget ); /* установка структуры обратного вызова */ cbinfo.reason_subtype = 0; cbinfo.event = event; cbinfo.cbdata = NULL; /* автоподсветка виджета с фокусом должна вызвать ARM */ if( widget->flags & Pt_AUTOHIGHLIGHT ) { PtSetArg( &arg, Pt_ARG_FLAGS, Pt_HIGHLIGHTED, Pt_HIGHLIGHTED); PtSetResources( widget, 1, &arg ); cbinfo.reason = Pt_CB_ARM; PtInvokeCallbackList( basic->arm, widget, &cbinfo ); } /* вызовем обратный вызов получения фокуса */ cbinfo.reason = Pt_CB_GOT_FOCUS; PtInvokeCallbackList( basic->got_focus, widget, &cbinfo ); return Pt_CONTINUE; }
Тип: Наследуемый
Этот метод используется только подклассами PtBasic'а. Он вызывается, когда виджет теряет фокус. Этот метод не подключен. Если ваш класс определяет метод Потери Фокуса, Вы будете должны или вызвать PtSuperClassLostFocus(), чтобы сохранить автоматическое подсвечивание и поведение метода Потери Фокуса уровня виджета, или реализовать поведение в методе Потери Фокуса вашего класса. Вот выборка из кода для PtBasic:
static basic_lost_focus( PtWidget_t *widget, PhEvent_t *event ) { PtBasicWidget_t *basic =( PtBasicWidget_t *) widget; PtCallbackInfo_t cbinfo; PtArg_t arg; PhRect_t wrect, rect = widget->extent; if( (widget->flags & Pt_FOCUS_RENDER) && ( basic->flags & Pt_DAMAGE_ON_FOCUS ) ) if( basic->fill_color == Pg_TRANSPARENT ) { PhTranslateRect( &rect, (PhPoint_t*)PtCalcCanvas( widget->parent, &wrect ) ); PtDamageExtent( widget->parent, &rect ); }else PtDamageWidget( widget ); cbinfo.reason_subtype = 0; cbinfo.event = event; cbinfo.cbdata = NULL; if( widget->flags & Pt_AUTOHIGHLIGHT ) { PtSetArg( &arg, Pt_ARG_FLAGS, 0, Pt_HIGHLIGHTED ); PtSetResources( widget, 1, &arg ); cbinfo.reason = Pt_CB_DISARM; PtInvokeCallbackList( basic->disarm, widget, &cbinfo ); } cbinfo.reason = Pt_CB_LOST_FOCUS; PtInvokeCallbackList( basic->lost_focus, widget, &cbinfo ); return Pt_CONTINUE; }
Тип: Наследуемый
Этот метод используется только подклассами PtBasic'а. Он устанавливает или очищает флаг Pt_OPAQUE виджета (ресурс Pt_ARG_FLAGS) и флаг Pt_RECTANGULAR класса виджета.
Когда флаг Pt_OPAQUE установлен для виджета, это означает, что виджет рисуется по полной области размеров виджета. Это позволяет библиотеке виджетов быть умной относительно изменения виджета, потому что она знает, что ничто ниже виджета не должно быть перерисовано. Этот флаг существенен для создания немерцающих эффектов. Если любая часть виджета прозрачна (то есть любой виджет ниже может быть виден), флаг Pt_OPAQUE должен быть очищен. Вот выборка из кода для PtBasic:
static void basic_calc_opaque( PtWidget_t *widget ) { PtBasicWidget_t *basic = (PtBasicWidget_t *) widget; /* если виджет прозрачен, или вокруг него не может быть непрозрачно */ if ( basic->fill_color == Pg_TRANSPARENT || basic>roundness ) widget->flags &= ~Pt_OPAQUE; else /* должен быть установлен флаг RECTANGULAR класса */ if ( widget->class_rec->flags & Pt_RECTANGULAR ) { widget->flags |= Pt_OPAQUE; basic_opaque_rect( widget ); } } static void basic_opaque_rect( PtWidget_t *widget ) { if( widget->flags & Pt_HIGHLIGHTED ) memcpy( &widget->opaque_rect, &widget->extent, sizeof( PhRect_t ) ); else PtCalcCanvas( widget, &widget->opaque_rect ); }
Действия виджета используются, чтобы сделать виджет интерактивным. Например, когда Вы нажимаете виджет кнопку, то можете видеть, что он вжимается и затем отжимается снова. Это достигается установкой необработанных обратных вызовов чувствительными к определенным событиям Фотона. Путь, которым виджет взаимодействует с событиями, определяет его поведение.
Список обратных вызовов, Pt_SET_RAW_CALLBACKS (смотрите раздел "Таблица ресурсов класса виджета" ранее в этой главе), определяет ответ виджета, если он отличается от поведения его суперклассов. Этот метод определен тем же способом, как и Pt_CB_RAW. Основное различие в том, что необработанный список обратного вызова класса вызывается перед необработанным списком обратного вызова пользователя. Вот выборка из кода для PtBasic:
static PtRawCallback_t callback = { Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE | Ph_EV_BUT_REPEAT | Ph_EV_BOUNDARY, basic_callback }; static PtArg_t args[] = { ... { Pt_SET_RAW_CALLBACKS, &callback }, ... };
В примере выше, всякий раз, когда виджет получает одно из этих четырех событий (Ph_EV_BUT_PRESS, Ph_EV_BUT_RELEASE, Ph_EV_BUT_REPEAT или Ph_EV_BOUNDARY), вызывается функция basic_callback(). Эта функция может проверить тип события и действовать соответственно.
Для ясности, давайте пройдем через упрощенное описание процесса "щелканья" на виджете PtButton.
Сначала, PtButton получает событие Ph_EV_BUT_PRESS. Виджет интерпретирует событие нажатия, изменяет флаги виджета в Pt_SET (возможно вызывая повреждение и перерисовку виджета), и затем вызывает обратный вызов Pt_CB_ARM.
Когда пользователь отпускает кнопку мыши, PtButton получает событие освобождения Ph_EV_BUT_RELEASE. Виджет очищает флаг Pt_SET и затем вызывает обратные вызовы Pt_CB_DISARM и Pt_CB_ACTIVATE.
Действие выполняемое PtButton, когда кнопка отпущена, немного более сложно, потому что виджет фактически делающий работу это PtBasic, не PtButton. Класс PtButton не определяет никаких необработанных обратных вызовов, потому что обработка, сделанная PtBasic, достаточна. Класс PtBasic обрабатывает общие обратные вызовы Фотона нажатия, отпускания, повторения, активизации и меню для всех виджетов.
Тип: Подключенный вверх, останавливаемый
Список необработанных обратных вызовов класса используется, чтобы сделать виджет чувствительным к сообщениям необработанных событий Фотона. Это позволяет виджету определять определенное поведение, связанное с внешними событиями или взаимодействием с пользователем. Так как имеется очень многое, что может быть сделано в результате событий Фотона, убедитесь, что осмотрели типовые виджеты, находящиеся в /qnx4/phtk/src/widgets (виджет PtScrollbar хороший пример).
Возврат Pt_HALT из необработанного обратного вызова класса предотвращает любой суперкласс (или пользователя) от обработки события. Событие размножается через иерархию виджетов и может быть обработано родительским виджетом.
Возврат Pt_END из необработанного обратного вызова класса предотвращает любой суперкласс, пользователя или родительский виджет от обработки события. Это называется поглощением события. Вот пример, взятый из кода для PtTimer:
static timer_callback( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo ) { PtTimerWidget_t *timer = (PtTimerWidget_t *)widget; PtCallbackInfo_t cbi; data,cbinfo; cbi.reason = Pt_CB_TIMER_ACTIVATE; if( timer->state == Pt_TIMER_INITIAL ) cbi.reason_subtype = Pt_TIMER_INITIAL; else cbi.reason_subtype = Pt_TIMER_REPEAT; timer->state = Pt_TIMER_REPEAT; PtInvokeCallbackList( timer->activate, widget, &cbi ); if( timer->msec_repeat && timer->state == Pt_TIMER_REPEAT ) PtTimerArm( widget, timer->msec_repeat ); return( Pt_CONTINUE ); } // // Функция создания класса PtTimer // PtWidgetClass_t *PtCreateTimerClass( void ) { static const PtResourceRec_t resources[] = { Pt_ARG_AREA, Pt_CHANGE_PREVENT, 0, Pt_ARG_IS_STRUCT( PtTimerUnion_t, core.area ), 0, Pt_ARG_DIM, Pt_CHANGE_PREVENT, 0, Pt_ARG_IS_STRUCT( PtTimerUnion_t, core.area.size ), 0, Pt_ARG_POS, Pt_CHANGE_PREVENT, 0, Pt_ARG_IS_STRUCT( PtTimerUnion_t, core.area.pos ), 0, Pt_ARG_TIMER_INITIAL, timer_modify, 0, Pt_ARG_IS_NUMBER( PtTimerWidget_t, msec_value ), 0, Pt_ARG_TIMER_REPEAT, timer_modify, 0, Pt_ARG_IS_NUMBER( PtTimerWidget_t, msec_repeat ), 0, Pt_CB_TIMER_ACTIVATE, Pt_CHANGE_INVISIBLE, 0, Pt_ARG_IS_CALLBACK_LIST( PtTimerWidget_t, activate ), 0, }; static const PtRawCallback_t callback[] = { Ph_EV_TIMER, timer_callback }; static const PtArg_t args[] = { { Pt_SET_VERSION, 110}, { Pt_SET_STATE_LEN, sizeof( PtTimerWidget_t ) }, { Pt_SET_DFLTS_F, (long) timer_dflts }, { Pt_SET_EXTENT_F, (long) PtNullWidget_f }, { Pt_SET_REALIZED_F, (long) timer_realized }, { Pt_SET_UNREALIZE_F, (long) timer_unrealize }, { Pt_SET_RAW_CALLBACKS, (long) callback, 1 }, { Pt_SET_FLAGS, Pt_FORCE_UNREALIZE, Pt_FORCE_UNREALIZE }, { Pt_SET_RESOURCES, (long) resources, sizeof( resources ) / sizeof( resources[0] ) }, { Pt_SET_NUM_RESOURCES, sizeof( resources ) / sizeof( resources[0] ) }, }; return( PtTimer->wclass = PtCreateWidgetClass( PtWidget, 0, sizeof( args )/sizeof( args[0] ), args ) ); }
Этот раздел применим для создания классов виджетов PtContainer:
PtWidget --> PtBasic --> PtContainer --> MyContainer
Контейнерные виджеты расширяют класс виджета PtBasic рядом методов ограничений. Эти методы позволяют контейнеру корректироваться автоматически согласно изменениям, сделанным в его дочерних виджетах.
Расширение контейнерного класса показывается в коде примера ниже (взято из файла заголовка PtContainer.h):
typedef struct Pt_container_widget_class { PtBasicWidgetClass_t basic; void (*child_created_f)( ... ); int (*child_settingresource_f)( ... ); int (*child_gettingresource_f)( ... ); int (*child_realizing_f)( ... ); void (*child_realized_f)( ... ); void (*child_unrealizing_f)( ... ); void (*child_unrealized_f)( ... ); void (*child_destroyed_f)( ... ); void (*child_move_resize_f)( ... ); int (*child_getting_focus_f)( ... ); int (*child_losing_focus_f)( ... ); PtWidget_t * (*child_redirect_f)( ... ); } PtContainerClass_t;
Методы ограничения можно индивидуально разрешать или запрещать установкой или очисткой соответствующих битов container->flags. Вы можете разрешить или запретить все методы ограничения сразу, установив или очистив Pt_IGNORE_CONSTRAINTS.
Метод | Описание | Декларация ресурса |
---|---|---|
child_created_f | Создание Дочернего Виджета | Pt_SET_CHILD_CREATED_F |
child_settingresource_f | Установка Ресурса Дочернего Виджета | Pt_SET_CHILD_SETTINGRESOURCE_F |
child_gettingresource_f | Получение Ресурса Дочернего Виджета | Pt_SET_CHILD_GETTINGRESOURCE_F |
child_realizing_f | Реализация Дочернего Виджета | Pt_SET_CHILD_REALIZING_F |
child_realized_f | Дочерний Виджет Реализовался | Pt_SET_CHILD_REALIZED_F |
child_unrealizing_f | Дереализация Дочернего Виджета | Pt_SET_CHILD_UNREALIZING_F |
child_unrealized_f | Дочерний Виджет Дереализовался | Pt_SET_CHILD_UNREALIZED_F |
child_destroyed_f | Разрушение Дочернего Виджета | Pt_SET_CHILD_DESTROYED_F |
child_move_resize_f | Перемещение/Измение Размеров Дочернего Виджета | Pt_SET_CHILD_MOVED_RESIZED_F |
child_getting_focus_f | Получение Фокуса Дочерним Виджетом | Pt_SET_CHILD_GETTING_FOCUS_F |
child_losing_focus_f | Потеря Фокуса Дочерним Виджетом | Pt_SET_CHILD_LOSING_FOCUS_F |
child_redirect_f | Переадресация Дочернего Виджета | Pt_SET_CHILD_REDIRECT_F |
Для удобства библиотека создания виджетов Фотона позволяет Вам вызывать эти методы из суперкласса, используя обеспеченные функции. Для получения дополнительной информации, смотрите главу API Библиотеки Создания Виджетов.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_CREATED
Вызывается всякий раз, когда новый дочерний виджет создается в этом виджете или в одном из его зависимых виджетов. Вот выборка, взятая из кода для PtGroup:
static void child_created( PtWidget_t *widget, PtWidget_t *child ) { PtCallback_t callback = { group_exclusive_callback, NULL }; PtGroupUnion_t *group = (PtGroupUnion_t *)widget; PtArg_t argt[2]; int n = 0; callback.data = widget; if( group->basic.activate ) { PtSetArg( &argt[n++], Pt_CB_ACTIVATE, &group->basic.activate->cb, 0 ); } if( group->group.group_flags & Pt_GROUP_EXCLUSIVE ) { PtSetArg( &argt[n++], Pt_CB_ACTIVATE, &callback, 0 ); } if( n ) PtSetResources( child, n, argt ); }
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_REALIZING
Вызвается всякий раз, когда дочерний виджет находится в процессе реализации ниже этого контейнера в иерархии.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_REALIZED
Вызывается всякий раз, когда дочерний виджет реализован ниже этого контейнера в иерархии.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_MOVED_RESIZED
Вызывается всякий раз, когда дочерний виджет переместился или изменил размеры ниже этого контейнера в иерархии.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_UNREALIZING
Вызывается всякий раз, когда дочерний виджет находится в процессе дереализации ниже этого контейнера в иерархии.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_UNREALIZED
Вызывается всякий раз, когда дочерний виджет дереализован ниже этого контейнера в иерархии.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_DESTROYED
Вызывается всякий раз, когда прямой дочерний виджет этого виджета или прямой дочерний виджет одного из его подчиненных разрушен.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_SETTING_RESOURCE
Вызывается всякий раз, когда ресурс устанавливается на прямом потомке этого виджета или одном из его подчиненных.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_GETTING_RESOURCE
Вызывается всякий раз, когда ресурс получается от прямого потомка этого виджета или одного из его подчиненных.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_GETTING_FOCUS
Вызывается всякий раз, когда дочерний виджет этого виджета или одного из его подчиненных собирается получить фокус.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_LOSING_FOCUS
Вызывается всякий раз, когда дочерний виджет этого виджета или одного из его подчиненных собирается потерять фокус.
Тип: Наследуемый
Флаг ограничения: Pt_CHILD_REDIRECTOR
Контейнерные виджеты обеспечивают механизм для переадресации дочерних виджетов, когда они добавляются к контейнеру. Вы можете использовать этот механизм, чтобы предотвратить некоторые классы виджетов от добавления как прямых потомков или для переадресации этих дочерних виджетов другим контейнерам в пределах контейнера (эта возможность обычно используется виджетами PtCompound).
Функция переадресации дочерних виджетов определена в функции создания класса и указывает, где дочерние записи должны быть приложены в иерархии виджетов. Переадресация достигается установкой члена child_redirect_f структуры Pt_container_widget_class в функцию переадресации дочерних виджетов.
Параметры функции переадресации дочерних это указатель на виджет и тип класса виджета, добавляемого в контейнер. Используя эту информацию, функция переадресации дочерних решает, принять ли виджет в контейнер или переадресовывать виджет другому контейнеру, типа родительского контейнерного виджета.
Хороший пример виджет PtMenuBar. Этот виджет принимает только виджеты PtMenuButton. Его функция создания класса включает следущее:
{ Pt_SET_CHILD_REDIRECT_F, (long)menubar_redirect },
Функция menubar_redirect() выглядит следующим образом:
static PtWidget_t *menubar_redirect( PtWidget_t *menubar, PtWidgetClassRef_t *cref ) { if (cref != PtMenuButton ) return menubar->parent; return menubar; }
Виджет, возвращенный функцией, становится родителем добавляемого виджета.
Вы можете использовать PtCompoundRedirect() как заданная по умолчанию функция переадресации дочерних виджетов для любых контейнеров, которые не будут принимать другие виджеты. PtCompoundRedirect() переадресовывает создание дочернего виджета родителю контейнерного виджета. Это заставляет новый виджет стать родственником контейнерного виджета, а не дочерним виджетом контейнерного виджета.
![]() |
Если Вы устанавливаете функцию переадресации дочерних виджетов в вашем классе виджета, Pt_CHILD_REDIRECTOR установлен. Когда Вы создаете образец, этот бит автоматически выключается перед вызовом метода По Умолчанию. Он включается обратно после того, как формирование цепочки По Умолчанию закончено. Это позволяет Вам создавать зависимые дочерние виджеты в вашем методе По Умолчанию без необходимости очищать и устанавливать этот бит самостоятельно. |
При использовании контейнерных виджетов, Вы должны обеспечить ряд контейнерно определенных процессов в пределах фундаментальных методов в дополнение к общим для каждого виджета.
Чтобы позволить методы с контейнерным ограничением, установите соответствующие биты в container->flags. Вы можете включить все биты следующим образом:
ctnr->flags |= Pt_CONTAINER_CONSTRAINT_BITS;
Вызываются только методы ограничения, чьи биты включены. Если Вы включили бит и соответствующий метод ограничения неопределен, бит игнорируется. Например:
ctnr->flags |= Pt_CHILD_CREATED;
Для каждого биты установленного во флаге, Вы должны обеспечить метод ограничения в списке параметров функции создания класса:
static PtArg_t args[] = { ... { Pt_SET_CHILD_CREATED_F, child_created }, ... };
Функция child_created() должна изменить дочерний виджет или контейнер как требуется, чтобы удовлетворить ситуации.
![]() |
Механизм Общий Доступ Пользователя (CUA - Common User Access), встроенный в библиотеку Фотона, автоматически передает фокус вокруг приложения. Если Вы хотите предотвратить виджеты внутри контейнера от получения фокуса, установите флаг Pt_BLOCK_CUA_FOCUS. Виджет PtMenuBar делает этот (то есть Вы не может нажать клавишу Tab, чтобы переместить фокус от виджета вне строки меню к виджету внутри строки меню). |
Этот метод ответствен за определение "экранной недвижимости" виджета. Закрепление применяется в этом методе. Виджеты, подклассифицируемые под PtContainer, обычно вызывают метод Размерности PtContainer'а, чтобы сделать заключительное вычисление размеров и закрепить виджет согласно его флагам якоря. Когда размеры виджета рассчитаны, его флаг widget->extent_valid должен быть установлен в Pt_TRUE.
Следующий пример демонстрирует, как обработать закрепление, если Вы не позволили классу PtContainer сделать это для Вас (смотрите так же PtSuperClassExtent()):
mycontainerwidget_extent( PtWidget_t *widget ) { PtWidget_t *widget PhRect_t canvas, old_extent; PhArea_t area; // Сохраним старый размер для сравнения позже. old_extent = widget->extent; PhRectToArea( &old_extent, &area ); if( PtResizePolicy( widget ) ) { PhRect_t render; render.lr.x = render.lr.y = SHRT_MIN; render.ul.x = render.ul.y = SHRT_MAX; PtChildBoundingBox( widget, &canvas, &render ); PhTranslateRect( &render, &canvas.ul ); PtAttemptResize( widget, &render, &canvas ); } PtSuperClassExtent( PtBasic, widget ); widget->extent_valid = Pt_TRUE; // Контейнеры должны закрепить свои дочерние виджеты. Изменение должно минимизировать мерцание. PtStartFlux( widget ); if( widget->parent && widget->parent->extent_valid && (ctnr->anchor_flags & Pt_IS_ANCHORED ) && !( widget->class_rec->flags & (Pt_DISJOINT|Pt_DISCONTINUOUS) ) ) PtAnchorWidget( widget ); else if( !(ctnr->anchor_flags & Pt_ANCHORS_LOCKED ) && memcmp( &widget->area.size, &area.size, sizeof(PhDim_t) ) ) for( wlp = ctnr->ctnrs; wlp; wlp = next ) { next = wlp->next; if( ((PtContainerWidget_t *)wlp->widget)->anchor_flags & Pt_IS_ANCHORED ) PtAnchorWidget( wlp->widget ); } PtEndFlux( widget ); // Если размеры изменились, приспособьте новый размер. if( memcmp( &old_extent, &widget->extent, sizeof( old_extent ) ) ) { if( ( widget->flags & Pt_REALIZED ) && (widget->rid) ) PtCoreChangeRegion( Ph_REGION_ORIGIN | Ph_REGION_RECT, widget ); if( !(ctnr->anchor_flags & Pt_ANCHORS_LOCKED) && memcmp( &widget->area.size, &area.size, sizeof(PhDim_t) ) ) PtInvokeResizeCallbacks( widget ); } }
Если ваш контейнер создает любые зависимые виджеты с установленным флагов Pt_DELAY_REALIZE, они могут быть реализованы в методе Реализации.
Этот раздел применим к созданию виджетов класса PtCompound:
PtWidget --> PtBasic --> PtContainer --> PtCompound --> MyCompound
Суперкласс PtCompound поддерживает расширенные функциональные возможности, обеспеченные "экспортируемыми" зависимыми дочерними виджетами. Механизм экспорта позволяет пользователям устанавливать/получать ресурсы зависимых дочерних виджетов через составной виджет не определяя любой из этих ресурсов в составном виджете. Составные виджеты могут изменять или блокировать заданные по умолчанию ресурсы, наследуемые их экспортируемыми зависимыми дочерними виджетами.
![]() |
Виджеты не должны быть подклассами PtCompound, чтобы экспортировать зависимые виджеты. Однако, так как PtContainer обеспечивает мощные механизмы дочернего ограничения и переадресации дочерних виджетов, мы рекомендует, чтобы, если Вы создали виджет, который создает зависимые дочерние записи, то должны подклассифицировать его из PtContainer (не от PtCompound). Это существенно упрощает управление зависимыми дочерними виджетами. Это также делает виджет более легким для использования, так как не должны быть изучены новые ресурсы. |
Чтобы достигнуть такого механизма экспорта, составной класс расширяет класса виджета PtContainer определением, как показано ниже:
typedef struct Pt_compound_class { PtContainerClass_t container; ushort_t num_subordinates; ushort_t *subordinates; ushort_t num_blocked_resources; ulong_t *blocked_resources; } PtCompoundClass_t;
Члены эта структуры:
Вот типовая функция создания класса из PtComboBox:
// // Функция создания класса PtComboBox // PtWidgetClass_t *PtCreateComboBoxClass( void ) { static const PtResourceRec_t resources[] = { Pt_ARG_POS, Pt_CHANGE_RESIZE, 0, Pt_ARG_IS_STRUCT( PtComboBoxUnion_t, core.area.pos ), 0, Pt_ARG_DIM, combobox_modify_dim, 0, Pt_ARG_IS_STRUCT( PtComboBoxUnion_t, core.area.size ), 0, Pt_ARG_FLAGS, combobox_modify, 0, Pt_ARG_IS_FLAGS( PtWidget_t, flags ), 0, // ----- надрез: большое количество удаленных определений ресурсов ----- Pt_ARG_CBOX_ITEMS, set_list_res, get_list_res, 0, 0, Pt_ARG_CBOX_SPACING, set_list_res, get_list_res, 0, 0, Pt_ARG_CBOX_VISIBLE_COUNT, set_list_res, get_list_res, 0, 0, // ----- надрез: большое количество удаленных определений ресурсов ----- }; static const ushort_t subs[] = { offsetof( PtComboBoxWidget_t, text_wgt ), offsetof( PtComboBoxWidget_t, list_wgt ), }; static const PtRawCallback_t callback = { Ph_EV_KEY, combobox_callback, NULL }; static const ulong_t blocked[] = { Pt_ARG_SELECTION_MODE, Pt_ARG_SEL_INDEXES }; static const PtArg_t args[] = { { Pt_SET_VERSION, 110}, { Pt_SET_STATE_LEN, sizeof( PtComboBoxWidget_t ) }, { Pt_SET_DFLTS_F, (long) combobox_dflts }, { Pt_SET_FLAGS, Pt_TRUE, Pt_COMPOUND }, { Pt_SET_RAW_CALLBACKS, (long) &callback }, { Pt_SET_RESOURCES, (long) resources, sizeof( resources ) /sizeof( resources[0] ) }, { Pt_SET_NUM_RESOURCES, sizeof( resources ) / sizeof( resources[0] ) }, { Pt_SET_EXTENT_F, (long) combobox_extent }, { Pt_SET_CONNECT_F, (long) combobox_init }, { Pt_SET_NUM_SUBORDINATES, sizeof( subs ) /sizeof( subs[0] ) }, { Pt_SET_SUBORDINATES, (long) subs, sizeof( subs ) / sizeof( subs[0] ) }, { Pt_SET_NUM_BLOCKED_RESOURCES, sizeof( blocked ) / sizeof( blocked[0] ) }, { Pt_SET_BLOCKED_RESOURCES, (long) blocked, sizeof( blocked ) /sizeof( blocked[0] ) }, { Pt_SET_CHILD_MOVED_RESIZED_F, (long) combobox_child_resize }, { Pt_SET_GOT_FOCUS_F, (long) combobox_got_focus }, }; return( PtComboBox->wclass = PtCreateWidgetClass( PtCompound, 0, sizeof( args )/sizeof( args[0] ), args ) ); }
![]() |
В коде примера, показанном выше, виджет PtComboBox создает зависимые виджеты и устанавливает указатели text_wgt и list_wgt в методе По Умолчанию к соответствующему указателю на виджет. |
В следующем примере, класс виджета MyCompound создает зависимые виджеты PtText, PtProgress, PtScrollArea и несколько PtLabel. Виджеты PtText, PtProgress и PtScrollArea экспортируются, а виджеты PtLabel нет. Все ресурсы применяются к зависимым виджетам. Не требуется дополнительного кода для MyCompound:
... n = 0; PtSetArg( &argt[n], Pt_ARG_POS, &pos, 0 ); n++; PtSetArg( &argt[n], Pt_ARG_TEXT_STRING, "Текстовое поле", 0 ); n++; PtSetArg( &argt[n], Pt_ARG_SCROLL_AREA_MAX_X, 1000, 0 ); n++; PtSetArg( &argt[n], Pt_CB_SCROLLED_X, &callback, 1 ); n++; PtSetResources( MyCompound, n, argt ); ... n = 0;
Чтобы получить ресурсы впоследствии:
... n = 0; n = 0; PtSetArg( &argt[n], Pt_ARG_POS, &phpoint_ptr, 0 ); n++; PtSetArg( &argt[n], Pt_ARG_TEXT_STRING, &char_ptr, 0 ); n++; PtSetArg( &argt[n], Pt_ARG_SCROLL_AREA_MAX_X, &short_ptr, 0 ); n++; PtGetResources( MyCompound, n, argt ); ... n = 0;
Когда обратный вызов Pt_CB_SCROLLED_X вызван, первый параметр widget это указатель на MyCompound, не на подчиненного. Класс PtCompound также облегчает блокировку определенных ресурсов от использования любым подчиненным.
Что происходит, когда Вы экспортируете два или больше зависимых виджета, поддерживающих один и тот-же ресурс? Например, и кнопка и текстовое поле принимают ресурс Pt_ARG_TEXT_STRING; если они экспортируются без поддержки кода, то установка ресурса составного виджета установит ресурс обоих подчиненных.
При получении ресурса, значение будет получено от первого экспортируемого виджета, поддерживающего ресурс. Если Вы не хотите, чтобы это случилось, установите функцию переадресации ресурса в конце метода По Умолчанию составного виджета.
Вы можете иметь составной виджет, переназначающий ресурс (смотрите Pt_ARG_TEXT_STRING в примере выше) определяя его, затем используя функцию mod_f() (названную в члене поле mod_f структуры PtResourceRec_t), чтобы применить ресурс соответствующему подчиненному виджету. Смотрите PtSampCompound.c в каталоге /qnx4/phtk/src/widgets для большего количества примеров переназначения ресурсов.
Любые ресурсы, определенные для подкласса виджета PtCompound не будут автоматически применяться к зависимому виджету, экспортированному или нет. Если Вы определяете функции переадресации ресурса для всех изменяемых пользователем ресурсов подчиненных виджетов, рассмотрите подклассификацию вашего виджета ниже PtContainer вместо PtCompound.
Механизм экспорта обеспечивает механизм блокирования ресурса. Вы можете выборочно блокировать ресурсы, делая их недоступнымы подчиненным виджетам.
Предположим, что Вы создали составной виджет, включающий экспортируемый виджет PtSlider, и хотите, чтобы бегунок слайдера имел всегда один и тот-же размер -- блокирование доступа к ресурсу Pt_ARG_SLIDER_SIZE предотвратит слайдер от изменения размеров.
Вы можете также обнаружить, что у Вас более чем одно местонахождение одного типа виджета как зависимого виджета. Например, ваш виджет мог бы иметь вертикальную и горизонтальную полосы прокрутки. В этом случае, Вы должны блокировать Pt_ARG_SCROLL_POSITION и создать два новых ресурса: Pt_ARG_X_SCROLL_POSITION и Pt_ARG_Y_SCROLL_POSITION. Метод Установки Ресурсов устанавливал бы для каждого соответствующего зависимого виджета полосы прокрутки ресурс Pt_ARG_SCROLL_POSITION.
Класс PtCompound обеспечивает стандартную функцию переадресации дочерних виджетов названную PtCompoundRedirect(). Эта функция предотвращает пользователя от создания виджетов в вашем составном виджете и вместо этого переадресует виджет пользователя в другой контейнер. Для того, чтобы переадресовывать к другому виджету, переадресуйте создание дочернего виджета в функции создания класса:
{ Pt_SET_CHILD_REDIRECT_F, (long)PtCompoundRedirect },
В шаблоне для виджета PtSampCompound, новые дочерние виджеты переназначаются к одному из порожденных зависимых виджетов, scroll_area, вызовом PtValidParent() (описана в Справочное Руководство по Библиотеке - Library Reference Фотона):
PtWidget_t * PtSampContainerRedirect( PtWidget_t *widget ) { PtWidget_t *parent; if( ( parent = PtValidParent( samp->scroll_area, widget->class_ref ) ) == widget ) return PtWidgetParent( widget ); return( parent ); /* * Возвращение samp->scroll_area позволило бы дочернему виджету * быть созданному как прямому потомку samp->scroll_area. * Это может быть нежелательно, поскольку scroll_area это * контейнерный виджет, который переадресовывает свои дочерние виджеты. */ }
PtValidParent() удостаивает любые функции переадресации дочерних виджетов, существующих в зависимых виджетах и их подчиненных. PtValidParent() должна использоваться только, чтобы переадресовать происхождение зависимому виджету. Это предотвращает бесконечные циклы, когда функция переадресации дочернего виджета возвращает управление.
Составные виджеты требуют нескольких фундаментальных методов в дополнение к общим для каждого виджета.
Для составных виджетов, все экспортируемые зависимые виджеты должны быть созданы в методе По Умолчанию. Чтобы экспортировать виджеты, установите следующее в функции создания класса:
Ресурсы зависимых виджетов могут быть переназначены, перегружены или блокированы. Зависимые виджеты могут быть созданы, но не реализованы в методе По Умолчанию.
Для того, чтобы механизмы с контейнерным ограничением работали правильно, флаг Pt_PROCREATED должен быть установлен в каждом зависимом виджете, и ресурс Pt_ARG_DATA (не Pt_ARG_USER_DATA) должен указывать назад на родительский виджет. Иначе, Вы столкнетесь с ошибкой SIGSEGV.
![]() |
Ваш заказной виджет не должен устанавливать свой собственный ресурс Pt_ARG_DATA, потому что этот ресурс используется внутренне библиотеками Фотона. Является безопасным установка его в зависимых дочерних виджетах вашего виджета. |
Вот пример из PtComboBox:
static void combobox_dflts( PtWidget_t *widget ) { PtComboBoxUnion_t *combobox = (PtComboBoxUnion_t *)widget; PtArg_t args[13]; int n = 0; PtCallback_t callback; PtRawCallback_t raw_cb; combobox->core.flags |= Pt_HIGHLIGHTED | Pt_SET; combobox->core.flags &= ~Pt_GETS_FOCUS; combobox->core.resize_flags = Pt_RESIZE_XY_ALWAYS; combobox->basic.fill_color = Pg_LGREY; combobox->basic.margin_height = 0; combobox->basic.margin_width = 0; combobox->basic.flags = Pt_STATIC_GRADIENT | Pt_ALL_ETCHES | Pt_ALL_OUTLINES; widget->border_width = combobox->combobox.border_width = 2; combobox->combobox.butn_size.w = 13; combobox->combobox.butn_border_width = 2; combobox->combobox.butn_bot_border_color = Pg_DGREY; combobox->combobox.butn_top_border_color = Pg_WHITE; combobox->combobox.butn_color = Pg_GREY; combobox->combobox.flags = Pt_COMBOBOX_DAMAGE_BUTTON; callback.event_f = combobox_text_callback; callback.data = (void*)widget; n = 0; PtSetArg( &args[n], Pt_ARG_BEVEL_WIDTH, 0, 0 ); n++; PtSetArg( &args[n], Pt_ARG_MARGIN_HEIGHT, 2, 0 ); n++; PtSetArg( &args[n], Pt_ARG_MARGIN_WIDTH, 2, 0 ); n++; PtSetArg( &args[n], Pt_ARG_FLAGS, Pt_PROCREATED, Pt_PROCREATED ); n++; PtSetArg( &args[n], Pt_ARG_DATA, &widget, sizeof( widget ) );n++; PtSetArg( &args[n], Pt_CB_MODIFY_VERIFY, &callback, 1); n++; PtSetArg( &args[n], Pt_CB_MOTION_VERIFY, &callback, 1); n++; PtSetArg( &args[n], Pt_CB_ACTIVATE, &callback, 1); n++; PtSetArg( &args[n], Pt_CB_GOT_FOCUS, &callback, 1); n++; PtSetArg( &args[n], Pt_CB_LOST_FOCUS, &callback, 1); n++; PtSetArg( &args[n], Pt_ARG_RESIZE_FLAGS, Pt_RESIZE_Y_AS_REQUIRED, Pt_RESIZE_XY_BITS ); n++; PtSetArg( &args[n], Pt_ARG_BASIC_FLAGS, Pt_TOP_LEFT_INLINE | Pt_RIGHT_OUTLINE | Pt_FLAT_FILL, ~0 ); n++; combobox->combobox.text_wgt = PtCreateWidget( PtText, widget, n, args ); n = 0; callback.event_f = combobox_list_callback; callback.data = (void*)widget; raw_cb.event_f = combobox_action; raw_cb.event_mask = Ph_EV_BOUNDARY; raw_cb.data = combobox; PtSetArg( &args[n], Pt_ARG_BEVEL_WIDTH, 1 /* combobox->combobox.border_width */, 0 );n++; PtSetArg( &args[n], Pt_ARG_SCROLLBAR_WIDTH, combobox->combobox.butn_size.w +3, 0 );n++; PtSetArg( &args[n], Pt_ARG_SEL_MODE, Pt_SELECTION_MODE_SINGLE | Pt_SELECTION_MODE_AUTO, 0 );n++; PtSetArg( &args[n], Pt_ARG_FLAGS, Pt_PROCREATED | Pt_DELAY_REALIZE, Pt_GETS_FOCUS | Pt_ETCH_HIGHLIGHT | Pt_PROCREATED | Pt_DELAY_REALIZE | Pt_ETCH_HIGHLIGHT );n++; PtSetArg( &args[n], Pt_CB_SELECTION, &callback, 1 );n++; PtSetArg( &args[n], Pt_CB_LIST_INPUT, &callback, 1 );n++; PtSetArg( &args[n], Pt_CB_RAW, &raw_cb, 1 );n++; PtSetArg( &args[n], Pt_ARG_DATA, &widget, sizeof( widget ) );n++; PtSetArg( &args[n++], Pt_ARG_BASIC_FLAGS, 0, Pt_ALL_ETCHES | Pt_ALL_INLINES ); combobox->combobox.list_wgt = PtCreateWidget( PtList, widget, n, args ); n = 0; callback.event_f = combobox_action; callback.data = (void*)widget; PtSetArg( &args[n], Pt_CB_ARM, &callback, 1 ); n++; PtSetArg( &args[n], Pt_CB_REPEAT, &callback, 1 ); n++; PtSetResources( combobox->combobox.text_wgt, n, args ); combobox->container.flags |= Pt_AUTO_EXTENT | Pt_CHILD_MOVED_RESIZED; }
Метод Реализации это последняя функция-член класса, вызываеиая перед методом Рисования. В ней Вы реализуете зависимые виджеты, созданные в методе По Умолчанию. Вот пример из PtComboBox:
static int combobox_realized( PtWidget_t *widget ) { PtComboBoxWidget_t *combobox = (PtComboBoxWidget_t *)widget; long flags; if ( combobox->flags & Pt_COMBOBOX_STATIC ) PtRealizeWidget( combobox->list_wgt ); else { PtRealizeWidget( combobox->butn_wgt ); } return Pt_CONTINUE; }
До настоящего времени, класс виджета PtCompound является единственным классом, который переопределяет методы Полученныя и Установки Ресурсов, которые используются внутренне. Вы не должны устанавливать функцию для этого метода, если только Вы не намереваетесь дублировать поведение PtCompound.
Метод Разрушения должен уничтожать любые переназначенные списки обратных вызовов экспортируемых подчиненных виджетов, имеющих ресурсы обратных вызовов установленных в них.
![]() |
![]() |
![]() |
![]() |
Все мессаги сюда:yanich@inbox.ru |