Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Общее устройство X Window.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
79 Кб
Скачать
☆

XtCreateWidget( ) возвращает идентификатор созданного объекта. В следующем примере создается widget класса Core, имеющий ширину и высоту равные 100 и 150 пикселов соответственно.

. . . . . . .

Arg aReserv [ ] = { { XtNwidth, (XtArgVal) 100 },

{XtNheight, (XtArgVal) 150 },

};

/* Ресурсы и их значения */

Widget prShellParent; /* Родительский объект */

Widget prCoreWidget; /* Идентификатор объекта */

. . . . . . .

prCoreWidget = XtCreateWidget ("core", widgetClass, prShellParent, aReserv, XtNumber (aReserv));

. . . . . . .

Здесь XtNumber( ) — макрос, определяющий размер массива фиксированной длины.

Заметим также, что значение ресурса в массиве aReserv должно иметь тип, соответствующий данному ресурсу.

Вместо создания статического массива ресурсов можно заполнять его динамически, используя макрос XtSetArg(). Например, предыдущий фрагмент можно было бы переписать следующим образом:

. . . . . . .

Arg aReserv [5];

/* Используется для задания ресурсов */

int i = 0;

Widget prShellParent; /* Родительский объект */

Widget prCoreWidget; /* Идентификатор объекта */

. . . . . . .

XtSetArg (aReserv [i], XtNwidth, 100);

i++;

XtSetArg (aReserv [i], XtNheight, 150);

i++;

prCoreWidget = XtCreateWidget ("core", widgetClass,

prShellParent, aReserv, i);

. . . . . . .

В X11R4 и выше задавать ресурсы при создании widget можно более удобно. Для этого надо использовать процедуру

XtVaCreateWidget (String psName, WidgetClass prClass, Widget prParent, . . .);

На месте многоточия при вызове процедуры должен стоять завершающийся нулем список пар: "имя ресурса, его значение". Ниже приведен пример применения XtVaCreateWidget( ).

. . . . . . .

Widget prShellParent; /* Родительский объект */

Widget prCoreWidget; /* Идентификатор объекта */

. . . . . . .

prCoreWidget = XtCreateWidget ("core", widgetClass, prShellParent, XtNwidth, 100, XtNheight, 150, NULL);

. . . . . . .

Каждый родительский widget (за исключением shell-widget) управляет своими "потомками", т.е. распоряжается их расположением, размером, получением фокуса ввода и т.д. Например, в OSF/Motif некоторые объекты располагают свои "дочерние" widget в ряды и колонки, другие группируют "потомков" в "блоки" и т.д. Для того, чтобы "дочерний" мог управляться своим "родителем", его необходимо включить в соответствующий список. Для этого используется процедура

void XtManageChild (Widget prWidget);

Здесь единственный аргумент идентифицирует widget, которым будет управлять "родитель".

Xt предусматривает более удобную процедуру XtCreateManagedWidget() (XtVaCreateManagedWidget( )), которая создает widget и после этого автоматически вызывает функцию XtManageChild(). Аргументы указанной процедуры полностью идентичны аргументам процедуры XtCreateWidget( ) или XtVaCreateWidget( ). Заметим, однако, что иногда более удобно создать сначала группу "дочерних" widget, а затем сразу всех включить в список управляемых (managed) объектов. Для этого можно воспользоваться функцией

void XtManageChildren (WidgetList prWidgetChildren, Cardinal nChildrenNumber);

Здесь первый и второй аргументы задают массив подобъектов и число элементов в этом массиве соответственно.

Процедура XtRealizeWidget (Widget prWidget) создает окна заданного widget, его управляемых подобъектов и показывает их на экране. Этот процесс называется "реализацией" объекта. Заметим, что нельзя реализовать widget, если это не сделано предварительно с его "родителем".

Если объект реализован, то вызов функции XtManageChild() для любого его подобъекта автоматически реализует последний.

Целый ряд процедур Xt позволяют получать различную информацию о widget. Среди таких процедур укажем следующие.

Процедура XtIsRealized (Widget prWidget) позволяет проверить, реализован данный объект или нет.

Процедура XtDisplay (Widget prWidget) возвращает указатель на X структуру данных типа Display, которая используется данным widget.

Процедура XtScreen (Widget prWidget) возвращает для заданного объекта указатель на X структуру данных типа Screen.

Процедура XDestroyWidget (Widget prWidget) используется для уничтожения заданного widget и всех его "потомков": указанная процедура освобождает все ресурсы, используемые уничтожаемыми объектами.

Модификация и чтение ресурсов объекта

Для модификации ресурсов уже созданного widget приложение может использовать процедуру

void XtSetValues (Widget prWidget, ArgList prArgs, Cardinal nNumArgs);

Здесь prWidget — объект, ресурсы которого устанавливаются, второй и третий аргументы содержат список пар: "имя ресурса/его значение" и число таких пар соответственно. Например, следующий фрагмент кода позволяет установить ширину и высоту widget класса Core:

. . . . . . .

Arg aReserv[5];

/* Используется для задания ресурсов */

int i = 0;

Widget prShellParent; /* Родительский объект */

Widget prCoreWidget; /* Идентификатор объекта */

. . . . . . .

prCoreWidget = XtCreateWidget ("core", widgetClass, prShellParent, NULL, 0);

XtSetArg (aReserv[i], XtNwidth, 100);

i++;

XtSetArg (aReserv[i], XtNheight, 150);

i++;

XtSetValues (prCoreWidget, aReserv, i);

. . . . . . .

X11R4 и выше поддерживает также функцию

void XtVaSetValues (Widget prWidget, . . . );

При ее вызове вместо многоточия должен стоять завершающийся нулем список пар: "имя ресурса, его значение". Приведенный выше пример с использованием XtVaSetValues( ) выглядит следующим образом:

. . . . . . .

Widget prShellParent; /* Родительский объект */

Widget prCoreWidget; /* Идентификатор объекта */

. . . . . . .

prCoreWidget = XtCreateWidget ("core", widgetClass, prShellParent, NULL, 0);

XtVaSetValues (prCoreWidget, XtNwidth, 100, XtNheight, 150, NULL);

. . . . . . .

Xt позволяет получить текущее значение ресурса widget, используя процедуру

void XtGetValues (Widget prWidget, ArgList prArgs,Cardinal nNumArgs);

Здесь prWidget — это объект, значения ресурсов которого будут получены. Второй аргумент содержит список пар, каждая из которых задает имя ресурса и адрес, по которому будет сохранено его значение. Третий аргумент есть число таких пар. Например, приводимый ниже фрагмент кода позволяет получить текущее значение высоты созданного объекта.

. . . . . . .

Arg aReserv[5];

Dimension nHeight;

Widget prWidget;

. . . . . . .

XtSetArg (aReserv[0], XtNheight, &nHeight);

XtGetValues (prWidget, aReserv, 1);

. . . . . . .

В результате в переменную nHeight будет скопировано текущее значение высоты для созданного widget. Переменная, в которую копируется значение ресурса должна иметь соответствующий ему тип.

Начиная с X11R4 можно использовать процедуру

void XtVaGetValues (Widget prWidget, . . .);

При ее вызове вместо многоточия должен стоять завершающийся нулем список пар, задающих имена ресурсов и адреса, по которым будут сохранены их значения. Приведенный выше пример с использованием XtVaGetValues() выглядит следующим образом:

. . . . . . .

Dimension nHeight;

Widget prWidget;

. . . . . . .

XtVaGetValues (prWidget, XtNheight, &nHeight, NULL);

. . . . . . .

Динамические ресурсы объектов

Описанные нами ресурсы widget в большинстве своем задают статику объекта: размер, цвет и т. д. Но дело в том, что управляющий элемент предназначен для того, чтобы дать возможность пользователю производить определенные действия (например, вводить текст, выбирать элементы из списков данных, рисовать график и т.д.). Кроме того, widget должен соответствующим образом реагировать на запросы о перерисовке и прочая и прочая и прочая. Следовательно, управляющие элементы должны иметь возможность вызывать процедуры, осуществляющие эти действия. При этом ясно, что процедуры, поставляемые самой системой можно использовать только для выполнения некоторого набора стандартных действий. Для возможности же реализации разнообразных специфичных операций приложению необходимо предоставить механизмы, позволяющие устанавливать связь между управляющими элементами и процедурами самой программы, которые выполняют необходимые функции. В Xt предусмотрены следующие три способа (механизма) осуществления такой связи и передачи управления в процедуры пользователя:

- использование процедур обратного вызова (callback-процедур);

- использование action-процедур;

- использование обработчиков событий (event handler).

Рассмотрим каждый из них более подробно.

Процедуры обратного вызова (callback)

С каждым widget сопоставлен набор операций, которые над ним можно производить. Так, любой элемент может быть создан и уничтожен, нажимаемая кнопка (push button) может быть нажата с помощью мыши или клавиши пробел и т. д. Каждому из таких предопределенных действий соответствует ресурс объекта, значение которого — список процедур библиотеки Xt и самой программы, которые автоматически вызывактся, когда совершается предусмотренное действие. Эти процедуры и называют процедурами обратного вызова (callback-процедуры). Рассмотренные нами ресурсы widget имеют тип XtCallbackList.

Все widget имеют по крайней мере один список callback. Он соответствует операции уничтожения объекта и наследуется от класса Core. Имя ресурса XtNdestroyCallback.

Программа может добавлять и убирать процедуры в (из) список (списка) callback. Добавить функцию в список можно с помощью процедуры

XtAddCallback (Widget prWidget, String psCallbackName, XtCallbackProc pProcedure, XtPointer pUserData);

Здесь prWidget задает объект, список которого модифицируется, psCallbackName есть имя списка, pProcedure добавляемая функция, pUserData — указывает на данные, передаваемые callback-процедуре при ее вызове.

Каждая процедура обратного вызова должна иметь прототип:

void CallbackProc (Widget prWidget, XtPointer pUserData, XtPointer pCallData);

Здесь первый аргумент задает widget, в списке которого находится функция. Второй аргумент указывает на данные, передаваемые из программы в процедуру. Третий аргумент указывает на данные, подготовленные для callback самой Xt или пакетом, построенным на ее основе (например, OSF/Motif). Обычно это структура, содержащая дополнительную информацию о действии, приведшем к вызову функции.

Для модификации списка процедур обратного вызова можно также использовать функцию

void XtAddCallbacks (Widget prWidget, String psCallbackName, XtCallbackList pCallbacks);

которая позволяет задавать несколько callback одновременно для одного и того же списка.

Здесь первый аргумент задает widget, чей список callback-процедур меняется. Его имя определяется вторым аргументом функции. Третий аргумент задает сами процедуры и передаваемые им параметры. Этот аргумента имеет специальный тип, определяемый следующим образом:

typedef struct {

XtCallbackProc callback; /* Указатель на процедуру */

caddr_t client_data; /* Указатель на данные */

} XtCallbackRec, *XtCallbackList;

Здесь первое поле задает callback-процедуру , а второе поле используется для передачи ей при вызове некоторых данных. При обращении к XtAddCallbacks() последний элемент массива pCallbacks должен быть равен NULL.

Удалить процедуру из списка callback можно с помощью функции XtRemoveCallback().

Использование action-процедур

Описанный в предыдущем пункте механизм использования callback-процедур достаточно прост и удобен, но имеет и существенный недостаток. В частности, указанные процедуры не могут вызываться в ответ на действие, не определенное для данного класса объектов. Например, в OSF/Motif класс XmDrawingArea (область для рисования) поддерживает список callback- процедур, вызываемый, когда widget получает фокус ввода. Однако, этого явно недостаточно, чтобы реализовать более сложное взаимодействие с пользователем.

Наряду с callback-процедурами, Xt Intrinsics поддерживает еще один механизм, позволяющий пользователю связывать код программы с widget. Указанный механизм состоит в использовании процедур — ответов на действия (action-процедур).

Как уже отмечалось ранее, action-процедура — это функция, которая вызывается в ответ на определенные события, порождаемые сервером. Они, в свою очередь, могут быть связаны с теми или иными действиями пользователя — нажатием на кнопку мыши, нажатие клавиш клавиатуры и т. д.

Процесс создания и подключения таких процедур состоит из следующих шагов, описываемых ниже.

Сначала создается специальная таблица действий (action table), связывающая символические имена действий (action) с указателями на соответствующие action-процедуры.

Регистрация созданной таблицы. Для этого можно использовать процедуру XtAppAddActions( ) или XtAddActions( ).

Создание таблицы соответствия (мы также будем употреблять термин таблица трансляции, английский эквивалент — translation table). Каждый ее элемент есть пара последовательность событий / имя (или имена) действия. Таблица размещается в файле ресурсов программы или непосредственно в ее коде. В последнем случае перед использованием таблица должна быть переведена процедурой XtParseTranslationTable( ) во внутренне представление Xt и зарегистрирована для объекта с помощью XtAugmentTranslations( ) или XtOverrideTranslations( ). Подробно формат таблицы соответствия описан ниже.

С учетом представленных шагов вызов action-процедуры, когда в widget происходит какое-то событие (события) , производится следующим образом:

- Xt проверяет для данного widget таблицу трансляции; если в ней такого события нет, то ничего не делается;

- если событие есть, то по нему определяются имена соответствующих действий;

- сканируется зарегистрированная "таблица действий", и по именам определяются адреса процедур; когда адрес становится известен, соответствующая функция вызывается.

Рассмотрим более подробно, что представляют собой таблица действий и таблица трансляции.

Первая из них — это массив структур типа XtActionRec, который определяется следующим образом:

typedef struct {

String string;