Руководство программиста в Photon (1037671), страница 27
Текст из файла (страница 27)
pterm -z
Когда Вы щёлкаете на кнопке "Debug Application" в диалоге "Build+Run", PhAB создаёт pterm, запускающий Ваше приложение. Вывод программы появляется в окне pterm. Опция -z оставляет окно pterm открытым вплоть до явного закрытия. Для получения более полной информации по pterm см. "Справочник утилит QNX6". Вы можете даже использовать printf() и gdb вместе, установив принимаемый по умолчанию отладчик в:
pterm gdb
Когда Вы щёлкните на кнопке "Debug Application" в диалоге "Build+Run", PhAB запускает pterm, который запускает gdb, запускающий Ваше приложение. Вы можете затем использовать gdb и видеть печатаемый программой вывод.
Все изменения, сделанные Вами в установках "Build Preferences", сохраняются не как глобальные установки, а вместе с самим приложением.
Включение в Ваше приложение не-PhAB файлов
Ваше приложение может включать файлы, которые были созданы не в PhAB, но Вам необходимо сообщить PhAB'у, как их отыскать.
Мультиплатформенные приложения
PhAB генерирует пустой список следующих файлов в директории src, и Вы можете его редактировать:
indHfiles | Не PhAB-шные хеадер-файлы. Например: MYHDR=../header1.h ../header2.h |
indOfiles | Не PhAB-шные файлы объектных модулей. Например: MYOBJ=file1.o file2.o |
indSfiles | Не PhAB-шные файлы исходного кода. Например: MYSRC=../file1.c ../file2.c |
Помните о необходимости задания файловых имён относительно местонахождения файлов Makefile. Для мультиплатформенного приложения они являются относительными к директории платформы:
-
хеадер-файлы и файлы исходного кода обычно располагаются в родительской директории src, так что их имя начинается с ../
-
объектные модули обычно располагаются в той же директории, что и файлы Makefile
Одноплатформенные приложения
Одноплатформенные приложения из более ранних версий Photon не имеют файлов indHfiles, indOfiles и indSfiles. Вместо этого Вы находите MYHDR, MYOBJ и MYSRC в Вашем файле Makefile и можете там задавать имена файлов.
Помните о необходимости задания файловых имён относительно местонахождения файла Makefile. Для одноплатформенного приложения они являются относительными к директории src.
Добавление библиотек
Если Ваше приложение использует библиотеку, которая по умолчанию не включена в Makefile, Вы можете её добавить, отредактировав следующие переменные:
-
LDFLAGS – используется при линковке вместо статических библиотек Photon'а.
-
SDFLAGS – используется при линковке вместо библиотек совместного доступа Photon'а.
Создание результирующей DLL как приложения PhAB
Вы можете создать приложение PhAB как DLL, однако не существует опции PhAB, позволяющей Вам это сделать. PhAB ничего не знает о создании DLLей; существует библиотека PhAB, позволяющая Вам преобразовать приложение PhAB в DLL.
Приложение, загружающее Вашу DLL, должно быть приложением PhAB, так что, по существу, библиотека PhAB инициализирована.
Даже несмотря на то, что PhAB позволяет Вам при старте устанавливать функцию инициализации и окна открытия, они игнорируются, когда Ваше приложение является DLL. Это происходит потому, что обычно запуск выполняется путём вызова функции main(), а в DLL функция main() не вызывается. Не пытайтесь также вызывать её из своего собственного кода.
Компилирование и линковка
Вообще Вы можете преобразовать любое приложение (как создание PhAB'ом, так и нет) в DLL, добавив -shared к флагам компилятора и линковщика (и вероятнее всего добавляя расширение so или dll к имени файла). Вам необходимо также установить для линкера опцию -Bsymbolic, чтобы быть уверенным, что локально определённые символы, используемые DLL, не будут переписаны другими символами с такими же именами из исполняемого файла.
Чтобы выполнить эти изменения для приложения PhAB, следует сделать в Makefile следующее:
-
Добавить -shared к CFLAGS
-
Добавить -shared -Wl, -Bsymbolic к LDFLAGS и SDFLAGS.
-
Найти все случаи появления исполниемого имени и добавить к нему расширение so или dll.
Инициализация DLL
Обычно DLL определяет функцию инициализации, которую вызывает приложение после того, как оно вызвало функцию dlopen() для загрузки DLL. Функция инициализации Вашей DLL требует полный путь к DLL.
Перед вызовом какого-либо кода PhAB функция инициализации должна вызвать ApAddContext() подобным образом:
ApAddContext(&AbContext, fullpath);
Аргументами здесь являются:
AbContext – | глобальная структура данных, которую PhAB перемещает в abmain.c |
| Эта структура имеет одно и то же имя во всех приложениях PhAB или DLL, так что Вы должны линковать Вашу DLL с опцией -Bsymbolic, как упомянуто выше. |
fullpath – | полный путь к DLL, подходящий для передачи в функцию open(). |
Вы можете вызвать функцию ApAddContext() более одного раза, но Вы должны отслеживать, как много раз Вы её вызывали.
ApAddContext() возвращает 0 в случае успешного выполнения или –1 при неудаче. Не выполняйте вызов какой бы то ни было функции Ap*, если вызов функции ApAddContext() завершился неудачей.
Выгрузка Вашей DLL
Когда приложение готово выгрузить DLL, оно обычно вызывает в DLL функцию очистки. В функции очистки Вашей DLL Вы должны:
-
Закрыть все базы данных виджетов, открывавшиеся Вашей DLL
-
Уничтожить все виджеты PhAB, принадлежащие Вашей DLL
-
Если Ваша DLL определила классы виджетов, вызвав функцию ApAddClass(), удалить их, вызвав функцию ApRemoveClass()
-
Вызвать функцию ApRemoveContext() подобным образом:
ApRemoveContext(&AbContext);
Вы должны вызвать ApRemoveContext() столько раз, сколько раз Вы успешно вызывали ApAddContext(). После того как Вы вызвали ApRemoveContext(), Ваша DLL не должна вызывать какие-либо функции PhAB.
Глава 9. Работа с программным кодом
PhAB делает простым создание пользовательского интерфейса с приложением. Как только PhAB сгенерировал заготовки программного кода для Вашего приложения, Вам необходимо написать ту часть, которая делает приложение что-то выполняющим. Эта глава описывает, как работать с программным кодом для приложения PhAB.
Она включает следующие разделы:
-
Переменные и декларации
-
Глобальный хеадер-файл
-
Имена функций и файлов
-
Функция инициализации
-
Установочные функции модулей
-
Функции ответных реакций кодового типа
-
Типы данных о геометрии
-
Таймеры
-
Меню инициализации
-
Задержка обновления и принудительное обновление экрана
Для получения информации об использовании в программе Photon нитей см. раздел "Параллельные операции".
Переменные и декларации
Переменные и декларации виджетов
PhAB создаёт глобальные переменные и декларации для каждого созданного Вами модуля, и каждого виджета, имеющего уникальное имя экземпляра. Это делает простым доступ к виджетам из Вашего программного кода приложения.
Глобальная переменная представляет имя виджета и определена в файле abvars.h. Каждая глобальная переменная принимает такую форму:
-
ABN_widget_name – где widget_name является именем виджета или именем экземпляра модуля, который Вы определили в панелях управления ресурсами или ответными реакциями. Значение этой переменной является уникальным в пределах всего приложения.
Декларация представляет указатель на экземпляр виджета и определена а файле abdefine.h. Этот файл, который включается во все файлы с кодом на языке С Вашего приложения, также определяет внешнюю ссылку на глобальные переменные. Каждая декларация принимает такую форму:
-
ABW_widget_name – где widget_name является именем виджета или именем экземпляра модуля, который Вы определили в панелях управления ресурсами или ответными реакциями.
PhAB не создаёт декларации ABW_... для модулей меню или пунктов меню. Обычно меню не живут достаточно долго, так что декларации для них не очень-то полезны. Если Вам необходимо изменять ресурсы PtMenu, создайте установочную функцию для модуля меню и делайте работу там. См. раздел "Установочные функции модулей" ниже.
Когда PhAB обнаруживает уникальное имя экземпляра, он генерирует имя глобальной переменной и декларацию виджета. Например, если Вы изменили имя экземпляра виджета класса PtButton – на "done", PhAB сгенерирует следующее:
-
ABN_done
-
ABW_done
Глобальная переменная и декларация виджета будут иметь силу только после того как виджет будет создан, и до тех пор, пока не будет уничтожен.
Использование глобальной переменной и декларация виджета
Давайте теперь посмотрим несколько примеров того, как Вы можете использовать глобальное имя и декларацию виджета из программного кода приложения. Во-первых, вот пример использования глобальной переменной ABN_done и функции ApName() для проверки конкретного виджета в ответной реакции:
int mycallback(PtWidget_t * widget, ...) {
/* проверка конкретного виджета */
if (ApName(widget) = = ABN_done) {
/* выполнение обработки кнопки */
}
return(Pt_CONTINUE);
}
Следующий пример использует ABW_done, чтобы изменить цвет фона виджета done на красный (для получения более полной информации см. главу "Управление ресурсами в программном коде приложения"):
int mycallback(PtWidget_t * widget,...) {
PtSetResource(ABW_done, Pt_ARG_FILL_COLOR, Pg_RED, 0);
return(Pt_CONTINUE);
}
Помните, что глобальная переменная и декларация виджета будут иметь силу только после того, как виджет будет создан, и до тех пор, пока не будет уничтожен.
Обработка множества экземпляров окна
Если у Вас имеется более чем один экземпляр модуля окна, отображаемых одновременно, то у Вас будут проблемы, связанные с получением доступа к виджетам в окне. Проблема произрастает из того факта, что ABW_instance_name для любого виджета в модуле окна указывает на последний созданный экземпляр этого виджета. Если у Вас имеется более одного экземпляра окна, то у Вас имеется и более одного созданного экземпляра виджетов внутри окна.
Пусть, скажем, Вы имеете следующий модуль окна:
Рис. 9-1. Простое окно поиска
Примем, что имена экземпляров следующие:
-
search_win для окна
-
name_txt для текстовой области
-
search_btn для кнопки
Если у Вас на экране одновременно имеется два экземпляра окна и пользователь щёлкнул на кнопке "Search", как Вы получите значение в текстовом виджете "Name"? Поскольку имеются два экземпляра окна, существует и два экземпляра текстового виджета. ABW_name_txt указывает на последний созданный экземпляр текстового виджета.
Решение основано на том факте, что для ссылки на оба экземпляра виджета name_txt может использоваться ABN_name_txt, обеспечивающий Вас указателем на виджет в том окне, которое содержит нужный текстовый виджет. Это осуществляется использованием функции ApGetWidgetPtr():
PtWidget_t *window_wgt, *text_wgt;
text_wgt = ApGetWidgetPtr(window_wgt, ABN_name_txt);
Где Вы получите window_wgt? В вышеприведенном случае Вы имеете ответную реакцию кодового типа на кнопке "Search". Первым параметром, передаваемым кодовой ответной реакции, является указатель на виджет кнопки "Search". Для получения указателя на окно, содержащее кнопку "Search", Вы можете использовать функцию ApGetInstance(). Таким образом ответная реакция станет такой:
int search_callback(PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo) {
char *name;
PtWidget_t *window_wgt, *txt_wgt;