Руководство программиста в Photon (953920), страница 30
Текст из файла (страница 30)
ABN_draw_group, ABN_draw_align, NULL);
Изменение текста пунктов меню
Для изменения текста пункта меню, например, замены команды на её противоположную, Вы можете использовать функцию ApModifyItemText(). Её аргументы следующие:
-
указатель на модуль меню. Например, если имя экземпляра объекта модуля меню – draw_menu , передайте в качестве первого параметра &draw_menu.
-
глобальная переменная ABN_... для пункта меню
-
новый текст
Например, наше меню "Draw" может иметь пункт, который должен быть либо "Group" (сгруппировать), либо "Split" (разгруппировать), в зависимости от того, какой объект выбрал пользователь. Мы можем изменить текст пункта draw_group в меню draw_menu с помощью следующего кода:
ApModifyItemText()(&draw_menu, ABN_draw_group, "Split");
Чтобы получить текущий текст пункта, вызовите функцию ApGetItemText().
Генерирование пунктов меню
Иногда Вам может потребоваться генерировать пункты меню в ходе выполнения задачи. Например, меню "Window" PhAB'а включает список модулей в Вашем приложении. Чтобы сгенерировать пункты меню, добавьте пункт-функцию в Ваш модуль меню (как описано в разделе "Создание пунктов-функций" в главе "Работа с модулями") и отредактируйте сгенерированную PhAB'ом заготовку функции.
Например, если Ваш модуль draw_menu включает пункт-функцию, который вызывает функцию add_shapes(), PhAB сгенерирует следующий код:
int add_shapes (PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo)
{
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget=widget, apinfo=apinfo, cbinfo=cbinfo;
return (Pt_CONTINUE);
}
Параметры, переданные этой функции, не используются. Мы используем функцию PtCreateWidget(), чтобы создать пункты меню, которые обычно являются виджетами PtMenuButton. Как описано в главе "Манипулирование ресурсами в программном коде приложения", чтобы установить начальные значения для ресурсов, мы можем использовать тот же тип списка аргументов, который мы использовали с функцией PtSetResourses(). Например, чтобы добавить пункт "Rectangle" с клавишей быстрого доступа "R":
PtArg_t args[2];
PtWidget_t *new_item;
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Rectangle", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "R", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
Вторым параметом в вызове PtCreateWidget() является родитель виджета; когда Вы генерируете пункты меню, он должен быть установлен в Pt_DEFAULT_PARENT. Это делает новый пункт потомком текущего меню или подменю. Не вызывайте в этом случае функцию PtSetParentWindget(). Далее, мы хотим прикрепить к новому пункту функцию ответной реакции. Мы должны сделать это вручную; PhAB не создаёт для этого заготовку функции. Например, ответная реакция для нашего нового пункта может быть такой:
int rect_callback ( PtWidget_t *widget, void *client_data, PtCallbackInfo_t *cbinfo)
{
.......
}
Эта ответная реакция похожа на код ответной реакции, генерируемой PhAB. Её аргументами являются:
widget Указатель на выбранный пункт меню
client_data Произвольные данные, передаваемые ответной реакции.
Это отличается от кода ответной реакции PhAB, которой в качестве второго аргумента передаётся apinfo.
cbinfo Указатель на общую структуру ответной реакции Photon'а. Структура предоставляет информацию, относящуюся к виджету, вызвавшему ответную реакцию, событие Photon'а и некоторые данные по ответной реакции, специфические для виджета. Формат данных зависит от класса виджета и типа ответной реакции. Для получения более полной информации см. описание PtCallbackInfo_t в "Справочнике виджетов".
Последнее, что нам надо сделать – это добавить ответную реакцию в список ответных реакций пункта меню Pt_CB_ACTIVATE, используя функцию PtAddCallback():
PtAddCallback(new_item, Pt_CB_ACTIVATE, rect_callback, NULL);
Последний аргумент в вызове функции PtAddCallback() задаёт то, что будет передано как аргумент client_data ответной реакции. Для получения более полной информации см. раздел "Ответные реакции" в главе "Управление виджетами в программном коде приложения".
Давайте сведём всё это вместе:
int rect_callback( PtWidget_t *widget, void *client_data, PtCallbackInfo_t *cbinfo)
{
...
}
int
add_shapes (PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo)
{
PtArg_t args[2];
PtWidget_t *new_item;
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget=widget, apinfo-apinfo, cbinfo=cbinfo;
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Rectangle", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "R", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
PtAddCallback (new_item, Pt_CB_ACTIVATE, rect_callback, NULL);
/* Повторить всё вышеприведенное для других форм */
return (Pt_CONTINUE);
}
Создание подменю
Вы можете создать подменю в меню, созданном для функции-пункта меню, как показано ниже:
-
Создать кнопку меню для каскадного меню, установив Pt_ARG_BUTTON_TYPE в Pt_MENU_RIGHT или Pt_MENU_DOWN, как потребуется.
-
Сохранить указатель на текущий родительский виджет, вызвав функцию Pt_GetParent():
menu=PtGetParentWidget();
-
Создать новый виджет PtMenu и установить Pt_MENU_CHILD в ресурсе нового меню Pt_ARG_MENU_FLAGS.
PtMenu является контейнером, так что это новое меню становится текущим принятым по умолчанию родителем.
-
Создать пункты подменю, как описано выше.
-
Восстановить принимаемого по умолчанию родителя из сохранённого значения, вызвав PtSetParentWidget():
PtSetParentWidget(menu);
-
Продолжить добавление пунктов в верхнем меню, если требуется.
Этот пример показывает, как генерировать подменю, а также как client_data могут быть использованы для ответных реакций класса для идентификации пункта, выбранного из меню:
/* Меню с подменю */
/* Стандартные хеадеры */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Инструментальные хеадеры */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>
/* Локальные хеадеры */
#include "abimport.h"
#include "proto.h"
/* Константы для форм в меню */
#define RECTANGLE 1
#define CIRCLE 2
#define DOT 3
#define BLOB 4
#define POLYGON 5
int ShapeMenuCB( PtWidget_t *widget, void *client_data, PtCallbackInfo_t *cbinfo )
{
int shape_chosen = (int) client_data;
widget=widget, client_data=client_data, cbinfo=cbinfo;
/* Эта ответная реакция использует клиентские данные, чтобы */
/* определить, какая форма была выбрана */
switch (shape_chosen) {
case RECTANGLE: ...
break;
case CIRCLE : ...
break;
case DOT : ...
break;
case BLOB : ...
break;
case POLYGON : ...
break;
default : printf ("Неизвестная форма: %d\n", shape_chosen);
}
return (Pt_CONTINUE);
}
int add_shapes( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )
{
PtArg_t args[3];
PtWidget_t *menu, *new_item;
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Rectangle", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "R", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
PtAddCallback ( new_item, Pt_CB_ACTIVATE, ShapeMenuCB, (void *) RECTANGLE );
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Circle", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "C", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
PtAddCallback ( new_item, Pt_CB_ACTIVATE, ShapeMenuCB, (void *) CIRCLE );
/* Создание кнопки меню для подменю */
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Miscellaneous", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "M", 0);
PtSetArg (&args[2], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, 0 );
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 3, args);
/* Сохранение текущего принятого по умолчанию родителя */
menu = PtGetParentWidget();
/* Создание подменю. Оно становится новым принимаемым по умолчанию родителем */
PtSetArg (&args[0], Pt_ARG_MENU_FLAGS, Pt_MENU_CHILD, Pt_MENU_CHILD);
new_item = PtCreateWidget( PtMenu, Pt_DEFAULT_PARENT, 1, args);
/* Добавление пунктов в подменю */
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Dot", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "D", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
PtAddCallback ( new_item, Pt_CB_ACTIVATE, ShapeMenuCB, (void *) DOT );
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Blob", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "B", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
PtAddCallback ( new_item, Pt_CB_ACTIVATE, ShapeMenuCB, (void *) BLOB);
/* Восстановление текущего принятого по умолчанию родителя */
PtSetParentWidget (menu);
/* Продолжение добавления пунктов в верхнее меню */
PtSetArg (&args[0], Pt_ARG_TEXT_STRING, "Polygon", 0);
PtSetArg (&args[1], Pt_ARG_ACCEL_KEY, "P", 0);
new_item = PtCreateWidget( PtMenuButton, Pt_DEFAULT_PARENT, 2, args);
PtAddCallback ( new_item, Pt_CB_ACTIVATE, ShapeMenuCB, (void *) POLYGON);
return( Pt_CONTINUE );
}
Задержка и принудительное обновление изображения на экране
Если Ваше приложение выполняет одновременно изменения в большом количестве виджетов, Вы можете захотеть задержать обновление экрана до тех пор, пока не завершатся все изменения. Это может дать уменьшение мерцания, и в некоторых случаях улучшить производительность Вашего приложения.
Вы можете задержать обновление:
-
всех виджетов Вашего приложения – библиотеки Photon'а записывают какие-либо изменения, но не перерисовывают виджеты.
-
заданного контейнера и его потомков – библиотеки даже не записывают изменения.
Глобально
Библиотеки Photon'а используют "счётчик удержаний", позволяющий Вам задерживать обновление экрана для Вашего приложения в целом:
-
Когда счётчик удержаний ненулевой, экран не обновляется. Для увеличения значения счётчика удержаний вызывается функция PtHold().
-
Когда Вы модифицируете виджет, библиотеки помечают его как "повреждённые".
-
Когда счётчик удержаний равен 0, библиотеки восстанавливают повреждённые виджеты как нормальные. Чтобы уменьшить значение счётчика удержаний, вызываются функции PtRelease() или PtUpdate() (эти две функции идентичны).
Для получения более полной информации об этих функциях см. "Справочник библиотечных функций Photon'а".
Для конкретного контейнера
Библиотеки Photon'а используют "счётчик изменений", позволяющий Вам задерживать обновление изображения для конкретного контейнера. Когда счётчик изменений ненулевой и Вы модифицируете контейнер или его потомков, виджеты не помечаются как "повреждённые". Что происходит, когда значение счётчика изменений опять возвращается в ноль, зависит от того, какие функции Вы используете:
PtStartFlux()
PtEndFlux()
Когда счётчик изменений контейнера приходит в ноль, Вы должны явно повредить области, которые хотите восстановить.
PtContainerHold()
PtContainerRelease()
Когда счётчик изменений контейнера приходит в ноль, весь контейнер в целом помечается как повреждённый.
PtContainerHold() и PtContainerRelease() более простые в использовании, поскольку Вам не надо определять, какие виджеты или области Вам необходимо повреждать. Однако это может приводить к большему мерцанию, чем в случае использования функций PtStartFlux() и PtEndFlux(). Если Вам необходимо определить, находится ли контейнер или любой из его родителей в текущий момент в изменении, используйте PtIsFluxing().
Для получения более полной информации по этим функциям см. "Справочник библиотечных функций Photon'а".
Принудительное обновление
Для немедленного обновления повреждённых областей изображения Вы можете в любой момент использовать вызов функции PtFlush(). Функция PtFlush() игнорирует счётчик удержаний и не изменяет его значение. Если контейнер находится в изменении и Вы модифицируете его или его потомков, библиотеки Photon'а не помечают виджеты как повреждённые, так что функция PtFlush() не будет их восстанавливать.
Комбинирование удержаний для всего приложения, удержание контейнеров и вызовов функции PtFlush() может дать непредсказуемый результат. Например, если Вы удерживаете всё приложение, повреждаете часть контейнера, удерживаете контейнер, модифицируете его, и затем вызываете функцию PtFlush(), библиотеки восстановят повреждение – отобразив какую бы то ни было порцию модификации, которая оказала воздействие на повреждённую область.
Глава 10. Манипулирование ресурсами в коде приложения
В этой главе описано, как Вы можете устанавливать и получать значения ресурсов виджетов из Вашего приложения. Глава включает:
-
Списки аргументов
-
Установка ресурсов
-
Получение ресурсов
Хотя Вы и можете устанавливать начальные значения ресурсов виджетов в PhAB'е, Вам, вероятно, понадобится получить доступ к ним из своего кода. Например:
-
когда появляется диалог, Вам может понадобится предварительно инициализировать какие-то отображаемые данные, так что Вы будете устанавливать ресурсы;
-
когда пользователь введёт значение в виджете PtText, набрав некий текст, Вам, возможно, понадобится это значение в Вашей программе, так что Вы будете получать ресурсы.
Дополнительно, если Вы используете функцию PtCreateWidget(), чтобы приписать значение (instantiate) виджету в Вашем коде, Вы можете задавать его ресурсам какие-то первоначальные значения.