Руководство программиста в Photon (1037671), страница 37
Текст из файла (страница 37)
Вы можете использовать внутренние связи, чтобы:
-
Создать модуль PhAB внутри кода приложения. Используя связь ответной реакции, Вы можете напрямую связать виджет с модулем приложения PhAB. Но иногда Вам необходимо вместо этого создавать модуль из Вашего программного кода. Чтобы это сделать, используйте внутреннюю связь. Вот несколько общих ситуаций, когда Вы будете использовать внутреннюю связь для создания модуля:
-
Когда Ваше приложение может отображать один из двух различных модулей, основанных на одном и том же состоянии внутри приложения.
-
Когда Вам надо управлять генеалогией модуля, вместо того чтобы использовать принимаемую в PhAB по умолчанию (по умолчанию новый модуль является потомком базового окна).
-
Когда Вы хотите отобразить меню при нажатии пользователем правой кнопки мыши.
-
Получить доступ и отобразить модули картинок. Вы используете модули картинок главным образом для того, чтобы заменить содержимое существующих контейнерных виджетов, таких как PtWindow или PtPanelGroup.
Заметьте, что когда Вы создаёте модуль картинки, используя ApCreateModule(), Вы должны задать родительский контейнерный виджет.
-
Открыть базы данных виджетов. Более подробно см. "Использование баз данных виджетов".
Создание внутренних связей
Чтобы создать внутреннюю связь:
-
Выберите пункт "Internal Links" в меню "Application" или нажмите <F4>. Вы увидите диалог "Internal Module Links":
Рис. 13-1. Диалог "Internal Module Links"
-
Щёлкните на опции <NEW>, если она ещё не выбрана
-
Выберите требующийся Вам тип модуля
-
Заполните области в разделе информации о связи модуля – см. ниже
-
Щёлкните на "Apply", затем щёлкните на "Done"
Вы можете создавать только по одной внутренней связи для каждого модуля.
Области диалога "Internal Module Links" включают:
-
Name – Содержит имя модуля. Чтобы выбрать имя из списка существующих модулей, щёлкните на кнопке рядом с этой областью.
-
Location – определяет, где появится этот модуль; см. "Позиционирование модуля" в главе "Работа с модулями".
-
Setup Functaion – задаёт функцию, которая будет вызываться, когда модуль реализуется (необязательная). Чтобы редактировать функцию, щёлкните на иконке рядом с этой областью. Более подробно см. в разделе "Установочные функции модуля" в главе "Работа с программным кодом".
-
Called – Определяет, вызывается ли установочная функция перед тем, как модуль реализуется, после того, или – и до и после.
-
Apply – Принимает все изменения
-
Reset – Восстанавливает всю информацию о внутренней связи в её перевоначальном состоянии.
-
Remove – Удаляет выбранную внутреннюю связь из списка связей модулей.
Использование внутренних связей в Вашем программном коде
Декларации
Для каждой внутренней связи, определённой в Вашем приложении, PhAB генерирует декларацию, так чтобы Вы могли идентифицировать и получить доступ к связи.
Поскольку PhAB извлекает имя декларации из имени модуля, каждый модуль может иметь только одну внутреннюю связь. Это может показаться ограничением, но PhAB предоставляет относящиеся к модулям функции (см. ниже), позволяющие Вам изнутри Вашего программного кода переделать установочную функцию модуля и месторасположение.
При создании имени декларации PhAB берёт имя модуля и добавляет ABM_ в качестве префикса. Так, например, если Вы создаёте внутреннюю связь к модулю с именем mydialog, PhAB создаст декларацию ABM_mydialog.
Функции внутренней связи
Декларация используется следующими функциями API PhAB'a:
ApCreateModule() | Позволяет Вам вручную создавать модули, спроектированные в PhAB'е. Модуль, созданный этой функцией, ведёт себя точно так же, как если бы он был непосредственно связан связью ответной реакции. Например, если Вы определяете месторасположение и установочную функцию для внутренней связи, модуль появится в этом заданном месте и будет вызвана установочная функция. Более того, ответные реакции виджетов, горячие клавиши и всё такое прочее тоже активизируется. |
ApModuleFunction() | Позволяет Вам изменить установочную функцию, присоединённую к внутренней связи. |
ApModuleLocation() | Позволяет Вам изменить местоположение модуля на экране, присоединённое к внутренней связи. |
ApModuleParent() | Позволяет Вам изменить родителя модуля окна или диалога, связанного внутренней связью. Эта функция употребляется только для внутренних связей к модулям окон и диалогов. |
ApOpenDBase() | Позволяет Вам открыть модуль, присоединённый через внутреннюю связь как база данных виджетов. |
Для получения более полной информации об этих функциях см. "Справочник библиотечных функций Photon'а".
Пример – отображение меню
Вот так Вы можете отобразить меню, когда пользователь нажмёт правую кнопку мыши, поместив её указатель на виджет:
-
В PhAB создайте модуль меню. Дайте ему имя, скажем my_menu.
-
Создайте внутреннюю связь (см. раздел "Создание внутренних связей" настоящей главы), как описано выше. Для выпадающего меню, обычно Вам потребуется, чтобы модуль располагался относительно виджета либо относительно указателя мыши.
-
Выберите виджет, связанный с меню. Убедитесь, что в его Pt_ARG_FLAGS установлен флаг Pt_MENUABLE и сброшен Pt_ALL_BUTTONS.
-
Сгенерируйте код для Вашего приложения. PhAB создаст декларацию внутренней связи. В нашем случае она будет называться ABM_my_menu.
-
Каждый виджет, являющийся потомком PtBasic, имеет ресурс Pt_CB_MENU, который представляет из себя список ответных реакций, вызываемых, когда Вы нажимаете правую клавишу мыши при указателе мыши на виджете. Отредактируйте этот ресурс и создайте функцию ответной реакции, подобную этой:
int text_menu_cb( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) {
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;
ApCreateModule (ABM_my_menu, widget, cbinfo);
return( Pt_CONTINUE );
}
Параметр widget, передаваемый функции ApCreateModule(), используется, если меню позиционируется относительно виджета; аргумент cbinfo – если относительно указателя мыши.
-
Скомпилируйте, слинкуйте и запустите Ваше приложение. Когда Вы нажмёте правую клавишу на виджете, появится Ваше меню.
Использование базы данных виджетов
Модули картинок служат двум целям:
-
позволять приложению заменять содержание какого-либо контейнерного виджета;
-
служить в качестве баз данных виджетов.
Если Вы планируете использовать виджет в Вашем приложении несколько раз, база данных виджетов позволит Вам спроектировать виджет только однажды. Она также уберегает Вас от необходимости писать кучу кода. Всё, что Вы делаете – это предустанавливаете ресурсы виджета, и затем, используя функции API базы данных виджетов PhAB'а, создаёте копию виджета всякий раз, когда обычно создаёте виджет из своего программного кода.
Вот пример базы данных виджетов – это является частью базы данных виджетов, которую PhAB использует в своём собственном интерфейсе:
Рис. 13-2. Пример базы данных виджетов
Создание базы данных
Чтобы создать базу данных виджетов:
-
Создайте модуль картинки в своём приложении
-
Создайте внутреннюю связь к модулю картинки
-
Создайте виджеты, к которым Вам необходимо иметь доступ из Вашего программного кода.
Например, скажем, Вам надо в Вашем приложении много раз создавать некую иконку. Создав иконку внутри модуля картинки, Вы сможете создать при выполнении программы столько копий иконки, сколько Вам понадобится.
Предварительно прикреплённые ответные реакции
Кроме того, что можно предустановить все ресурсы виджета в модуле базы данных, Вы также можете предварительно прикрепить их ответные реакции. Когда Вы создаёте виджет динамически, будут также созданы все прикреплённые Вами ответные реакции.
Предустанавливая ресурсы и ответные реакции для виджета базы данных, Вы легко можете уменьшить объём кода, требуемого для динамического создания виджета, до одной-единственной строки.
Предварительное прикрепление ответных реакций работает только с модулями и функциями, которые являются частью Вашего исполняемого файла. Если Ваше приложение открывает внешний файл как базу данных виджетов, библиотека PhAB'а не будет в состоянии найти код, чтобы прикрепить ответную реакцию.
Назначение уникального имени экземпляра
Присвойте каждому виджету в базе данных виджетов уникальное имя – это позволит Вам ссылаться на виджеты при использовании функций API, относящихся к базам данным.
Создание динамической базы данных
Вы также можете создать базу данных виджетов, которую Вы сможете изменять динамически. Чтобы сделать это, откройте внешнюю базу данных виджетов – т.е. такую, которая не подвязана к Вашему исполняемому файлу – функцией ApOpenDBaseFile() вместо вызова функции ApOpenDBase(). Функция ApOpenDBaseFile() позволяет Вам получить непосредственный доступ к файлу модуля и открыть его как базу данных.
Открыв однажды файл модуля, Вы сможете копировать виджеты из этого файла в Вашу внутреннюю базу данных приложения и сохранять результирующую базу данных в новом файле, который Вы сможете впоследствии переоткрыть.
Функции базы данных виджетов
PhAB предлагает несколько вспомогательных функций, позволяющих Вам открыть базу данных виджетов и скопировать её виджеты в модули – Вы можете скопировать виджеты столько раз, сколько Вам понадобится. PhAB также предоставляет удобные функции, позволяющие Вам копировать виджеты между базами данных, создавать виджеты, удалять их, и сохранять базы данных виджетов.
ApOpenDBase(), ApCloseDBase() | Они позволяют Вам открывать и закрывать базу данных виджетов. Чтобы сразу обеспечить доступность базы данных, обычно используется функция ApOpenDBase() в функции инициализации приложения. |
ApOpenDBaseFile(), ApSaveDBaseFile() | Они позволяют Вам открыть и сохранить файл внешнего модуля как базу данных внутри Вашего приложения. |
ApAddClass() | Эта функция позволяет Вам указать, с какими классами виджетов Вы, вероятно, столкнётесь, когда вызовите ApOpenDBaseFile(). При линковке Вашего приложения только те виджеты, которые Вам требуются, будут подлинкованы к Вашему приложению. Если Вы получаете доступ к виджетам, которых нет в Вашем приложении, поскольку они находятся во внешней базе данных, Вы должны добавить их ко внутренней таблице классов, так чтобы они подлинковались на этапе компилирования. |
ApCreateDBWidget(), ApCreateDBWidgetFamily(), ApCreateWidget(), ApCreateWidgetFamily() | Они создают виджеты из базы данных виджетов. Функции ApCreateWidget() и ApCreateDBWidget() создают только один виджет, невзирая на класс виджета. Для виджета неконтейнерного класса функции ApCreateWidgetFamily() и ApCreateDBWidgetFamily() создают одиночный виджет; для виджета контейнерного класса они создают все виджеты внутри контейнера. Эти функции отличаются по родителю, используемому для виджетов:
Не используйте декларации, генерируемые для модуля картинки базы данных виджетов. Вместо этого используйте указатели, возвращаемые функцией ApCreateWidget() или ApCreateDBWidget(). |
ApCopyDBWidget() | Позволяет Вам копировать виджет из одной базы данных виджетов в другую. Обычно Вы используете эту функцию только тогда, когда динамически создаёте или сохраняете базу данных виджетов внутри Вашего приложения. |
ApDeleteDBWidget() | Удаляет виджет из базы данных виджетов |
ApGetDBWidgetInfo() | Получает информацию о виджете в базе данных виджетов, включая его имя, класс, родителя и уровень иерархии. |
ApGetImageRes() | Извлекает данные по ресурсам образа из виджета и использует эти данные для установки виджета, уже изображённого в Вашем приложении. Эта функция позволяет Вам добиться простейшей анимации. Если вы используете базу данных виджетов для создания виджетов, имеющих данные PhImage_t, прикреплённые к ним, не закрывайте базу данных функцией ApCloseDBase() до тех пор, пока эти виджеты не будут уничтожены. (Закрытие базы данных освобождает память, используемую для образа). Если Вы должны закрыть базу данных, убедитесь, что скопировали данные образа внутри программного кода Вашего приложения, и переустановите ресурс данных образа, так чтобы он указывал на Вашу новую копию. |
ApGetTextRes() | Эта функция позволяет Вам извлекать текстовую строку из базы данных виджета. Это полезно для многоязычных приложений, когда текст автоматически переводится, если включена поддержка языка. Для получения более полной информации см. приложение "Поддержка международных языков". |
ApRemoveClass() | Удаляет класс виджета. Если Вы загрузили DLL, которая определяет класс виджетов, Вы должны будете удалить их перед выгрузкой DLL. Для более полной информации см. раздел "Существование DLL в приложениях PhAB" главы "Генерация, компиляция и запуск программного кода на выполнение". |
Для получения более полной информации о функциях баз данных виджетов см. "Справочник библиотечных функций Photon".
Глава 14. Поддержка международных языков
PhAB имеет встроенную поддержку для приложений, требующих перевода на другие языки. Эта глава включает:
-
Соображения о проектировании приложений
-
Генерация языковой базы данных
-
Базы данных сообщений
-
Редактор языков
-
Запуск Вашего приложения на исполнение
-
Распространение Вашего приложения
Помня о нескольких соображениях в отношении проектирования, и затем следуя нескольким простым шагам, Вы сможете очень легко перевести Ваше приложение на другой язык без необходимости перекомпиляции или перестройки Вашего приложения:
-
PhAB генерирует базу данных для всех текстовых строк, встречающихся в Вашем приложении.
-
Эта текстовая база данных используется редактором языков PhAB'a, чтобы дать Вам возможность переводить каждую текстовую строку на другой язык.
-
Переведенные текстовые строки сохраняются в файле перевода и добавляются в Ваше приложение.
-
Чтобы запустить Ваше приложение на исполнение с другим языком, просто установите переменную окружения перед запуском приложения. Когда API PhAB'a построит окна приложения, диалоги и другие модули, он заменит текстовые строки другими, с новыми переводами. [Прим.пер.: не совсем так. Переменная окружения ABLANG "принимается" на этапе запуска сессии Photon'а, и экспорт нового значения влияния уже не оказывает. Поэтому не экспортом переменной, а записью соответствующей строки в файл /root/.ph/.ABLANG, из которого берёт значение переменной строка из файла /root/.profile, выполняется переключение языка. После чего необходим перезапуск сессии Photon'а].
Это так просто.
Соображения о проектировании приложения
В этом разделе представлены несколько соображений по поводу проектирования, которые помогут Вам создать приложение, независимое от языка. Проектируя и реализовывая Ваше приложение, Вы должны иметь в виду эти соображения, поскольку модификация приложения после её завершения будет более трудной.
Размер виджетов, основанных на тексте
Обычно, когда Вы проектируете приложение, Вы планируете окно, использующее виджеты, имеющие уже предустановленный по умолчанию текст приложения. Например, если Вы имеете кнопку "Done" в нижней части окна диалога, сама кнопка должна быть достаточно большой лишь в той мере, чтобы разместить текстовую строку "Done". Вы также разместите кнопку "Done" на основании её текущего размера. Это хорошо работает в приложениях, которые не требуют перевода, но станет причиной многих проблем в приложении, независимом от языка. Что будет, если переведенный текст будет состоять не из 4 символов, как по умолчанию, а из 12?
-
"Переводимая" кнопка может стать больше по размеру. В этом случае она может стать такой широкой, что будет писать поверх других виджетов окна. Это приведёт к тому, что приложение будет выглядеть хреново или убого спроектированным
или
-
Текст может быть обрезан внутри размера, заданного по умолчанию. В этом случае переводимый текст может стать нечитабельным, и пользователь не будет знать, что эта кнопка делает.
Например, эти кнопки слишком малы, чтобы быть приспособленными под переведенный текст: