Руководство программиста в Photon (953920), страница 33
Текст из файла (страница 33)
PtGetResources() возвращает 0 в случае успеха или –1, если случается ошибка. Возврат кода, равного –1, может указывать на то, что Вы пытаетесь получить значение ресурса, который для виджета не определён.
Получение одного ресурса
Если Вы получаете значение одного ресурса, проще использовать вместо функции PtGetResources() функцию PtGetResource(). Для функции PtGetResource() Вам нет необходимости устанавливать список аргументов. Аргументами PtGetResource() являются:
int PtGetResource (PtWidget_t *widget, long type, long value, long len);
widget – это указатель на виджет, ресурс которого мы получаем. Другие аргументы устанавливаются точно так же, как и в PtSetArg(), когда с использованием указательного метода получаете более одного ресурса.
Вот пример получения одного ресурса функцией PtGetResources() и указательного метода:
unsigned short *width;
PtArg_t arg;
PtSetArg( &arg, Pt_ARG_BEVEL_WIDTH, &width, 0 );
PtGetResources( widget, 1, &arg );
При использовании функции PtGetResource() код имеет такой вид:
unsigned short *width;
PtGetResource( widget, Pt_ARG_BEVEL_WIDTH, &width, 0 );
PtGetResource() возвращает указатель непосредственно во внутреннюю память виджета. Не пытайтесь модифицировать ресурс, напрямую используя этот указатель. Такая модификация не приведёт к ожидаемому эффекту и вызовет ошибки поведения виджета. Никогда не освобождайте указатель – результатом этого наверняка будет ошибка памяти или другая сходная ошибка. Использование указателя const поможет избежать таких проблем.
Изменение состояния виджета может сделать указатель потерявшим силу, используйте его сразу же.
Глава 11. Управление виджетами в исходном коде приложения
Мы рекомендуем Вам создавать пользовательский интерфейс Вашего приложения в PhAB – это проще, чем делать это в Вашем коде. Однако если интерфейс динамический, Вы, возможно, создаёте часть интерфейса "на лету".
Эта глава включает:
-
Создание виджетов
-
Задание порядка виджетов
-
Ответные реакции
-
Обработчики событий
-
Стили виджетов
Создание виджетов
Создание виджета в Вашем приложении требует немного больше работы, чем создание его в PhAB. Это потому, что PhAB заботится о куче физических атрибутов для Вас, включая размеры, местоположение и прочая. Если Вы создаёте виджет в своём коде, Вы должны будете сами установить эти ресурсы. Чтобы создать виджет из своего кода, вызовите функцию PtCreateWidget(). Её синтаксис следующий:
PtWidget_t *PtCreateWidget(
PtWidgetClassRef_t *class,
PtWidget_t *parent,
unsigned n_args,
PtArg_t *args );
Её аргументами являются:
class | Тип создаваемого виджета (напр., PtButton) |
parent | Родитель нового виджета. Если это Pt_DEFAULT_PARENT, новый виджет становится потомком родителя, принимаемого по умолчанию, которым является самый последний созданный виджет контейнерного класса. Если parent равно Pt_NO_PARENT, виджет не имеет родителя. |
n_args | Число элементов массива args |
args | Массив структур PtArg_t , который хранит Ваши установки для ресурсов виджета. Эти установки аналогичны тем, что используются для PtSetResources(); см. главу "Управление ресурсами в исходном коде приложения". |
Вы можете задать принимаемого по умолчанию родителя (используемого, если аргумент parent в вызове функции PtCreateWidget() равен Pt_DEFAULT_PARENT), вызвав функцию PtSetParentWidget(). Чтобы назначить для виджета другой контейнер, вызовите функцию PtReparentWidget().
Вот несколько заметок относительно виджетов, создаваемых в исходном коде приложения:
-
Виджет не реализуется, пока не реализуется контейнерный виджет. Если контейнер уже реализован, Вы можете вызвать функцию PtRealizeWidget(), чтобы реализовать новый виджет.
-
Если Вы создали виджет в модуле PhAB и затем уничтожили модуль, виджет тоже будет уничтожен. В следующий раз, когда модуль будет создан, он появится таким, каким он был задан в PhAB.
-
если Вы сохранили в виджете глобальный указатель, убедитесь, что при уничтожении виджета Вы сбросили указатель в NULL. Это легко сделать в ответной реакции Pt_CB_DESTROYED виджета. Ошибка, заключающаяся в несбрасывании глобального указателя (и проверки его перед использованием), является часто встречающимся источником проблем с виджетами, созданными через программный код.
Задание порядка виджетов
Порядок, в котором виджетам даётся фокус, зависит от порядка, в котором они были созданы или от порядка виджетов, заданного в PhAB (см. "Задание порядка виджетов" в главе "Создание виджетов в PhAB"). Самым задним виджетом является первый в установленном порядке перехода, самый передний является последним.
Если Вы создаёте виджеты программно, Вы можете создавать их в том порядке, в котором Вы хотите передавать им фокус, или же Вы можете использовать для изменения порядка следующие функции:
| Вставить виджет в иерархию семейства виджетов |
| Переместить виджет за спину всех своих братьев |
| Переместить виджет впереди всех своих братьев |
С другой стороны, Вы можете использовать ответную реакцию виджета Pt_CB_LOST_FOCUS (определённую для PtBasic), чтобы переписать порядок перехода путём передачи фокуса другому виджету.
В ответной реакции потери фокуса используйте функцию PtContainerGiveFocus(), чтобы передать фокус нужному виджету, и возвращайте для ответной реакции Pt_END, чтобы воспрепятствовать передаче фокуса первоначальной цели изменения фокуса.
Ответная реакция Pt_CB_LOST_FOCUS вызывается во второй раз, когда фокус перемещается от виджета к новой цели. Чтобы исключить бесконечную петлю, используйте статическую переменную для указания того, что эта ответная реакция уже перенаправила фокус.
Работа с семейством виджетов
Для работы с иерархией семейства виджетов могут использоваться следующие функции, и они могут быть полезны при установке порядка передачи фокуса:
PtChildType | Определяет взаимосвязь между двумя виджетами |
PtFindDisjoint() | Возвращает ближайший рассоединённый родительский виджет |
PtFindFocusChild() | Находит ближайший фокусируемый сыновний виджет |
PtFindGuardian() | Находит виджет, отвечающий за действие другого виджета |
PtGetParent() | Находит ближайший родительский виджет, совпадающий с заданным классом |
PtGetParentWidget() | Возвращает текущий действующий по умолчанию родительский виджет |
PtNextTopLevelWidget() | Получает указатель на следующий виджет верхнего уровня |
PtValidParent() | Идентифицирует действующего родителя виджета |
PtWidgetBrotherBehind() | Получает брата позади виджета |
PtWidgetBrotherInFront() | Получает брата впереди виджета |
PtWidgetChildBack() | Получает сына, самого заднего в контейнере |
PtWidgetChildFront() | Получает сына, самого переднего в контейнере |
PtWidgetFamily() | Проходит иерархию виджета задом наперёд |
PtWidgetParent() | Получает родителя виджета |
PtWidgetSkip() | Перескакивает к виджету в следующемй иерархии |
PtWidgetTree() | Проходит дерево виджетов спереди назад |
PtWidgetTreeTraverse() | Проходит иерархию семейства виджетов спереди назад |
Ответные реакции
Вы можете добавлять и удалять ответные реакции в Вашем программном коде так же, как и через PhAB – только обратите внимание на различия между двумя типами!
Добавление ответных реакций
Приложение регистрирует ответные реакции, манипулируя ресурсами ответной реакции виджета. Для этих ресурсов в классах виджетов Photon'а используется соглашение по именованию: они все начинаются с Pt_CB_.
Ответные реакции могут быть добавлены в список ответных реакций, хранимых для этих ресурсов, использованием функции PtAddCallbacks() для добавления в список нескольких функций ответных реакций или функции PtAddCallback() для добавления только одной. В любом случае первыми двумя аргументами функции являются виджет и имя ресурса ответной реакции, которая добавляется. Остальные аргументы зависят от того, какая функция используется.
В функции PtAddCallbacks() третьим аргументом является массив записей ответных реакций. Каждая запись содержит указатель на функцию ответной реакции и указатель на данные присоединённого клиента, которые будут передаваться функции ответной реакции при её вызове. Каждая из этих записей ответных реакций скопирована во внутренний список ответных реакций виджета.
Например, мы можем захотеть, чтобы, когда пользователь выбрал кнопку (т.е. нажал её), приложение выполнило некое действие. Класс PtButton виджетов предоставляет ресурс ответной реакции Pt_CB_ACTIVATE для уведомления приложения, когда кнопка нажата. Чтобы создать виджет и присоединить к этому ресурсу ответной реакции функцию ответной реакции, мы используем код такого вида:
{
PtWidget_t *button;
int push_button_cb( PtWidget_t *, void *, PtCallbackInfo_t *);
PtCallback_t callbacks[] = { {push_button_cb, NULL} };
...
button = PtCreateWidget(PtButton, window, 0, NULL);
PtAddCallbacks(button, Pt_CB_ACTIVATE, callbacks, 1);
}
где push_button_cb – имя функции приложения, которая должна вызываться, когда пользователь нажимает кнопку. Для определения списка ответных реакций используется структура PtCallback_t; более подробно см. "Справочник виджетов Photon'а".
Когда в список ответных реакций добавляется только одна функция ответной реакции (как в этом случае), проще использовать PtAddCallback(). Эта функция берёт указатель на функцию ответной реакции как третий аргумент и указатель на данные клиента как последний аргумент. Вышеприведенный фрагмент кода может быть записан более кратко таким образом:
{
PtWidget_t *button;
int push_button_cb( PtWidget_t *, void *, PtCallbackInfo_t *);
button = PtCreateWidget(PtButton, window, 0, NULL);
PtAddCallback(button, Pt_CB_ACTIVATE, push_button_cb, NULL);
}
Вы можете также передавать массив записей ответной реакции как значение для ресурса ответной реакции, когда используется список аргументов в связке с функцией PtCreateWidget() или PtSetResources(). Поскольку список ответных реакций является массивом, Вы должны задать базовый адрес массива как третий аргумент функции PtSetArg() и число элементов как последний аргумент. В этом случае записи ответной реакции добавляются к текущему списку ответной реакции, если он имеется. Это даёт нам другой способ задания ответной реакции для вышеприведенного примера:
{
PtArg_t arg[5];
int push_button_cb( PtWidget_t *, void *, PtCallbackInfo_t *);
PtCallback_t callbacks[] = { {push_button_cb, NULL} };
...