25. Разработка расширений

В DataExpress расширения бывают двух видов: функции и действия. Они разрабатываются средствами DataExpress и представляют собой скрипты на Pascal Script. В редакторе скриптов создается модуль расширений, пишется скрипт, затем используется в текущей базе или экспортируется для использования в других базах. В одном модуле могут быть расширения обоих видов. Расширения позволяют непрограммистам использовать дополнительный функционал. Большое количество расширений и исходников доступно на форуме.

Описание модуля

В специальном комментарии {@module .. @} пишется автор, версия, описание модуля расширений и, необязательно, ссылка на домашнюю страницу расширения.

{@module 
Author=Автор 
Version=1.0
HomePage=https://forum.mydataexpress.ru/viewtopic.php?f=16&t=2429
Description=Назначение модуля 
@}

Описание модуля

Всего 4 поля:

  • Author – информация об авторе.
  • Version – версия модуля.
  • HomePage - ссылка на домашнюю страницу расширения. Если используется, то в окне «Расширения» кнопка «Домашняя страница» станет активной. Также в описании функций, действий в заголовке появится многоточие - это ссылка на домашнюю страницу.
  • Description – краткое описание модуля. Описание может быть записано в несколько строк.

Данный комментарий необязательный, но если он указывается, то нужно строго соблюдать состав и последовательность полей: author, version, homepage, description. Информация о модуле отображается в окне «Расширения».

Функции

Этот вид расширений позволяет дополнить выражения новыми функциями. В специальном комментарии {@function … @} пишется спецификация функции.

{@function
OrigName=GetFormName
Name=FormName
Args=
Result=s
Group=Мои функции
Description=Эта функция возвращает имя текущей формы @}
 
function GetFormName: String; 
begin
  Result := Self.FormCaption;
end;
 
{@function
OrigName=ToWordsBel
Name=ToWordsBel
Args=n
Result=s
Group=Функции преобразования
Description=Эта функция возвращает число прописью на белорусском языке. @}
 
function ToWordsBel(N: Double): String; 
beginend;

В комментарии должны быть следующие параметры:

  • OrigName – исходное имя функции в модуле.
  • Name – имя функции, используемое в выражениях.
  • Args – типы аргументов:
    • n – число,
    • s – строка,
    • d – дата,
    • t – время,
    • b – логический,
    • v – любой тип.

Записывается, как несколько идущих подряд символов: nns, s, ds и т. д.

  • Result – тип результата. Используются те же символы, что и в Args.
  • Group – название группы, в которой будет находиться функция в окне «Функции».
  • Description – описание функции. Отображается в окне «Функции». Описание может быть записано в несколько строк. Можно использовать некоторые html-теги.

Нужно строго соблюдать состав и последовательность полей. В случае нарушения правил, компилятор выдаст ошибку. Комментарии могут находиться в любом месте модуля, но рекомендуется писать их перед функцией. Возможной проблемой является дублирование имен функций разными разработчиками модулей. Поэтому старайтесь давать функциям уникальные имена, например, добавляя какой-нибудь префикс: EX_EXEC, MY_FUNC, DA_FIRMGET и т. д.

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

В модулях выражений можно использовать переменную Self для доступа к текущей форме. Но нужно быть осторожным. Выражения могут выполняться не только в формах, но и в отчетах. Если выражение выполняется в отчете, то переменная Self = nil.

Действия

Действие описывается в специальных комментариях. Пример:

{@action
Id=D569B5E1-7575-445F-8DFB-54B5FF99595B
Target=button
OrigName=MyActionProc
Name=Некое действие
Group=Моя группа
UI=
<ui>
  <form name="form" caption="Выберите форму" />
  <field name="field" caption="Выберите поле" source="form" filter="number" />
  <grid name="grid" caption="Таблица" height="100" >
    <text name="text" caption="Название" />
    <checkbox name="checkbox" caption="Флажок" defaultvalue="1" />
  </grid>
  <expr name="expr" caption="Выражение" />
</ui>
Description=Описание действия
@}
procedure MyActionProc(FormName, FieldName: Variant; Grid: TVariantArray2d; Expr: Variant);
begin
end;

Параметры:

  • Id - уникальный идентификатор действия. Программа ищет действие по его идентификатору. Это любая последовательность символов, но лучше использовать для этого GUID. В редакторе скриптов GUID можно вставить комбинацией Ctrl-Shift-G.
  • Target - определяет, где можно применять действие: в форме, кнопке, при запуске базы или везде. Допустимые значения соответственно: form, button, main, all. При выборе действия в списке будут только допустимые действия. Данный параметр необязателен, но если он указывается, то должен идти после параметра id.
  • OrigName - имя процедуры или функции в модуле.
  • Name - название действия для пользователя.
  • Group - группа, к которой принадлежит действие. Возможно создание подгрупп. Для этого группы разделяются слешем, например: Группа/Подгруппа/Подгруппа. Сочетание группы и названия действия должно быть уникальным.
  • UI - описание интерфейса в формате XML. Компоненты используются для настройки действия.
  • Description - описание действия в формате html.

Описание интерфейса. Параметр UI

Компоненты действия Любое действие настраивается путем заполнения различных компонентов и выбора значений из списков. Состав компонентов, предназначенных для настройки действия, задается в параметре ui в формате xml. Каждому тегу соответствует определенный компонент, а именно:

  • text - поле для ввода текста;
  • number - поле для ввода числа;
  • checkbox - флажок;
  • file - поле с кнопкой выбора файла;
  • folder - поле с кнопкой выбора папки;
  • expr - поле для ввода выражения;
  • filter - поле для ввода выражения фильтра;
  • list - список значений;
  • form - список основных форм (без подчиненных);
  • childform - список подчиненных форм;
  • query - список запросов;
  • object - список объектов;
  • field - список полей;
  • component - список компонентов;
  • report - список отчетов;
  • template - список шаблонов;
  • color - цвет;
  • image - изображение из галереи;
  • divider - разделитель;
  • grid - таблица.

Теги имеют атрибуты:

  • name - имя компонента;
  • caption - поясняющая надпись;
  • height - высота таблицы;
  • width - ширина столбца таблицы;
  • required - обязательное;
  • defaultvalue - значение по умолчанию;
  • items - элементы списка;
  • source - компонент-источник;
  • form - форма, используемая в выражении фильтра;
  • filter - фильтр списка;
  • texthint - подсказка;
  • editing - редактирование списка;
  • noform - не использовать форму.

Рассмотрим несколько общих атрибутов, которые применяются во всех компонентах.

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

Caption - поясняющая надпись. Атрибут caption хоть и необязательный, но также важный атрибут. Он задает некий поясняющий текст над компонентом. В случае с флажком (checkbox), текст будет находится справа от флажка. В случае с разделителем (divider) текст будет непосредственно в разделителе.

Required - обязательное. Этот атрибут означает, что компонент обязательно должен быть заполнен или выбрано значение. Значение атрибута должно быть равно единице. Пример:

<text name="title" caption="Заголовок" required="1"/>

Атрибут не действует для компонентов grid, color, checkbox, divider.

DefaultValue - значение по умолчанию. Компонент может иметь заранее заданное значение. Если вы задаете значение по умолчанию для списка (list), убедитесь что значение совпадает с одним из возможных значений атрибута items, включая регистр символов. Для флажка возможно задание только одного значения по умолчанию - 1.

Texthint - подсказка. Если задан этот атрибут, то в компоненте появится подсказка, которая исчезает при заполнении компонента. Очень удобно использовать в качестве примера заполнения компонента. Действует только в следующих элементах: text, number, file, folder, expr, filter, image.

Text - поле для ввода текста

Один из самых простых компонентов - поля для ввода произвольного текста. В нем могут использоваться все общие атрибуты.

Number - поле для ввода числа

Единственное его отличие от компонента Text - это ввод только цифр. Допустимо вводить только целые числа без знака.

Checkbox - флажок

Данный компонент может принимать только два значения: 1 и 0, отмечено и неотмечено.

File - поле с кнопкой выбора файла

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

описание|маска|описание|маска|...|описание|маска

Например:

Файлы документов Word|*.docx;*.doc|Файлы таблиц Excel|*.xlsx;*.xls|Все файлы|*.*
Файлы PDF|*.pdf

Как видно из примера, маски файлов могут перечисляться через точку с запятой.

Folder - поле с кнопкой выбора папки

Компонент представляет собой поле для ввода текста с кнопкой выбора папки из стандартного диалога. Возможно ввести путь к папке непосредственно в поле ввода.

Expr - поле для ввода выражения

Компонент состоит из поля ввода выражения и кнопки, которая открывает редактор выражений. В компоненте могут использоваться атрибуты source или noform. Примеры использования:

<form name="myform" caption="Выберите форму"/>
<expr name="expr" caption="Выражение" source="myform"/>
<expr name="myexpr" caption="Выражение текущей формы"/>
<expr name="calc" caption="Выражение без формы" noform="1"/>

Атрибут source указывает форму (form или childform), поля которой можно использовать в выражении. В редакторе выражений атрибуту соответствует кнопка «Выбрать поле формы». Если source не указан, то такой формой считается текущая форма. В качестве значения source выступает имя компонента (атрибут name). Если вы не хотите, чтобы была возможность выбирать поля текущей формы, то укажите атрибут noform. Атрибуты source и noform не имеет смысла использовать вместе.

Filter - поле для ввода выражения фильтра

Компонент используется для ввода фильтра формы. Текст можно набирать прямо в компоненте или в редакторе выражений. Возможно использование атрибутов source, form и noform. Примеры:

<filter name="filter" caption="Простой фильтр текущей формы"/>
<form name="frm" caption="Выберите форму"/>
<filter name="filter2" caption="Фильтрация выбранной формы" source="frm"/>
<filter name="filter3" caption="Фильтрация выбранной формы и применение ее полей в выражении" source="frm" form="frm"/>
<filter name="filter4" caption="Фильтрация формы без использования полей текущей формы в выражении" source="frm" noform="1"/>

Атрибут source определяет форму, к которой применяется фильтр. В редакторе выражений ему соответствует кнопка «Выбрать поле источника». Атрибут form определяет форму, поля которой можно использовать в выражении. В редакторе выражений атрибуту соответствует кнопка «Выбрать поле формы». Если source или form не указаны, то будет использована текущая форма. Если вам необходимо исключить выбор поля формы, то используйте атрибут noform.

List - список значений

Компонент позволяет выбрать одно значение из списка или ввести свое значение. Список значений задается атрибутом items. Значения отделяются друг от друга точкой с запятой. По умолчанию компонент позволяет выбрать только значение из списка. Если вам необходимо дать возможность ввести свое значение, используйте атрибут editing. Примеры:

<list name="mylist" caption="Фиксированный список" items="Один;Два;Три;Четыре" defaultvalue="Один"/>
<list name="mylist2" caption="Редактируемый список" items="Красный;Оранжевый;Желтый;Зеленый" editing="1"/>

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

Form - список основных форм (без подчиненных)

Компонент позволяет выбрать форму из списка основных форм. Атрибут source может указывать на запрос (тег query) или отчет (тег report). В этом случае в списке будут формы из источников отбора.

ChildForm - список подчиненных форм

Компонент позволяет выбрать подчиненную форму из списка. Атрибут source может указывать на основную форму, которой принадлежат подчиненные формы. Если атрибут source не указан, то в списке будут подчиненные формы текущей формы. Кроме формы в атрибуте source может быть указан объект (object). В этом случае в списке будут подчиненные формы той формы, на которую ссылается объект. Примеры:

<childform name="tbl" caption="Подчиненная форма текущей формы"/>
<form name="frm" caption="Основная форма"/>
<childform name="tbl2" caption="Подчиненная формы выбранной формы" source="frm"/>
<object name="obj" caption="Объект"/>
<childform name="tbl3" caption="Подчиненная форма объекта" source="obj"/>

Query - список запросов

Компонент позволяет выбрать запрос из списка. Атрибут source указывает на форму, запросы которой будут в списке. Если атрибут не указан, в списке будут запросы текущей формы. В качестве source может быть указана не только основная форма (form), но и подчиненная форма (childform) или объект (object).

Object - список объектов

Компонент позволяет выбрать объект из списка. Атрибут source может указывать на форму (form или childform). Если source не указан, то список будет содержать объекты текущей формы.

Field - список полей

Компонент позволяет выбрать поле из списка. Атрибут source может указывать на форму (form или childform), запрос (query), отчет (report) или объект (object). Если source не указан, то в списке будут поля текущей формы. Атрибут filter позволяет показывать в списке поля определенного типа. Типы полей перечисляются через точку с запятой. Допустимые значения:

  • text - текстовые поля (текст, список, заметка),
  • number - число,
  • date - дата,
  • time - время,
  • object - объект,
  • counter - счетчик,
  • checkbox - флажок,
  • file - файл,
  • image - изображение.

Примеры:

<field name="field" caption="Все поля текущей формы"/>
<field name="field2" caption="Поля текущей формы определенного типа" filter="text;number;date"/>
<form name="frm" caption="Форма"/>
<field name="field3" caption="Поля выбранной формы" source="frm"/>
<object name="obj" caption="Объект"/>
<field name="field4" caption="Поле объекта" source="obj"/>
<report name="rp" caption="Отчет"/>
<field name="field5" caption="Поле отчета" filter="number;counter"/>

Component - список компонентов

Компонент позволяет выбрать какой-либо компонент из списка. Атрибут source может указывать на форму (form или childform) или объект (object). Если source не указан, то в списке будут поля текущей формы. Атрибут filter позволяет показывать в списке компоненты определенного типа. Типы компонентов перечисляются через точку с запятой. Допустимые значения:

  • TdxLabel - надпись;
  • TdxEdit - текст;
  • TdxCalcEdit - число;
  • TdxDateEdit - дата;
  • TdxTimeEdit - время;
  • TdxCounter - счетчик;
  • TdxMemo - заметка;
  • TdxCheckBox - флажок;
  • TdxComboBox - список;
  • TdxLookupComboBox - объект;
  • TdxObjectField - поле объекта;
  • TdxImage - фоновое изображение;
  • TdxDBImage - изображение;
  • TdxShape - фигура;
  • TdxFile - файл;
  • TdxGrid - таблица;
  • TdxQueryGrid - запрос;
  • TdxPivotGrid - сводная таблица;
  • TdxGroupBox - группа;
  • TdxPageControl - закладки;
  • TdxButton - кнопка;
  • TdxChart - диаграмма.

Пример:

<form name="myform" caption="Форма" />
<component name="mycmp" caption="Компонент" source="myform" filter="TdxEdit;TdxComboBox;TdxLabel;TdxButton" />

Report - список отчетов

Компонент позволяет выбрать отчет из списка.

Template - список шаблонов

Компонент позволяет выбрать шаблон из списка или ввести путь к шаблону вручную. Список заполняется шаблонами, хранящиеся в папке шаблонов и в ее подпапках.

Color - цвет

Компонент представляет из себя кнопку с выбранным цветом. При нажатии на кнопку открывается стандартный диалог выбора цвета. Значение по умолчанию может быть задано в виде названия цвета или шестнадцатиричного числа. Шестнадцатиричное число представляет собой значения красного, зеленого и синего цветов и задается по схеме: $BBGGRR, где BB - синий, GG - зеленый, RR - красный цвет. Значение каждого из цветов должно быть в пределах от 00 до FF. Доступные названия цветов: clBlack ($000000), clMaroon ($000080), clGreen ($008000), clOlive ($008080), clNavy, ($800000), clPurple ($800080), clTeal ($808000), clGray ($808080), clSilver ($C0C0C0), clRed, ($0000FF), clLime, ($00FF00), clYellow, ($00FFFF), clBlue ($FF0000), clFuchsia ($FF00FF), clAqua ($FFFF00), clLtGray ($C0C0C0), clDkGray ($808080), clWhite ($FFFFFF), clMoneyGreen ($C0DCC0), clSkyBlue ($F0CAA6), clCream ($F0FBFF), clMedGray ($A4A0A0). Специальные цвета: clNone ($1FFFFFFF) - нет цвета (кнопка заштрихована), clDefault ($20000000 - цвет, заданный в системе по умолчанию).

Image - изображение из галереи

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

Grid - Таблица

Вы можете задавать не просто отдельные компоненты, а целые массивы компонентов. Для этого используются таблицы. Синтаксис очень простой. Чтобы определить столбцы и типы компонентов, достаточно вышеперечисленные теги перечислить между тегами <grid>..</grid>.

Пример:

<form name="myform" caption="Форма" />
<grid name="fields" caption="Поля" height="150">
  <field name="field" caption="Поле" source="myform" filter="text" />
  <checkbox name="mychk" caption="Флажок" width="80" />
</grid>

Таблице можно задать высоту с помощью атрибута height. Текст заголовков берется из атрибута caption вложенных тегов. Если ширина width не задана, то ширина колонки определяется автоматически. Ширину колонок менять нельзя. Если в таблице определен только один компонент, то заголовок таблицы скрывается. Если в таблице определены зависимые компоненты (имеют атрибут source), то при изменении значения в родительском компоненте ячейки НЕ стираются. Символы внутри атрибутов <, > и « должны быть заменены на &lt; &gt; &quot; соответственно.

Проверка действия

Проверка действия описывается при помощи тегов if и ifgrid. Теги должны располагаться в параметре UI вместе с описанием компонентов, желательно после описания компонентов.

Тег if описывает одно условие проверки и состоит из следующих атрибутов:

  • expr - логическое выражение, синтаксис которого похож на синтаксис выражений DataExpress;
  • msg - сообщение, которое показывает программа в случае какого-либо несоответствия. В сообщении можно писать выражения, заключенные в обратные кавычки;
  • focus - имя компонента, на который следует установить фокус в случае несоответствия.

Атрибуты expr и msg обязательные. Когда логическое выражение expr истинно, программа показывает сообщение msg и если указан компонент в атрибуте focus, устанавливает фокус на компоненте и отображает значок рядом с компонентом на 2 секунды. На этом дальнейшая проверка прерывается и действие сохранить невозможно, пока не будет исправлена ошибка в настройках действия.

Чтобы выполнить проверку в таблице, необходимо заключить теги if в тег ifgrid. В теге ifgrid единственный обязательный атрибут:

  • grid - имя компонента таблицы (grid).

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

Синтаксис логического выражения

Синтаксис логического выражения в основном совпадает с синтаксисом выражений DataExpress. Текст можно заключать только в одинарные кавычки. Вместо полей в квадратных скобках, пишутся имена компонентов без скобок. Имя компонента - этом имя в атрибуте name соответствующего компонента в параметре UI, такого как form, field, component и т. д. Имена компонентов могут использоваться только как параметры функции. Функции, в отличии от функций в выражениях DataExpress, всегда пишутся со скобками. Ниже рассмотрим функции, которые можно применять в условии проверки.

GetText

Функция возвращает текст в компоненте. Если компонентом является флажок, то функция возвращает: '0' или '1'.

<if expr="GetText(form)=''" msg="Выберите форму." focus="form"/>
<if expr="GetText(checkbox)='1' | GetText(option)='Какая-то опция'" msg="Какое-то сообщение" focus="option"/>

GetNumber

Преобразует текст в число и возвращает в качестве результата. Если преобразование не удалось, возвращается 0. Если компонентом является флажок, то возвращаются значения: 0 и 1.

GetFieldType

Функция возвращает тип поля формы, запроса или отчета. Возвращаемое значение совпадает со значениями, указанными в атрибуте filter тега field. Если в соответствующем компоненте не выбрано значение, то функция возвращает пустую строку. Если по каким-то причинам функция не может найти поле в соответствующем источнике (который задается в атрибуте source), то функция возвращает '?'.

<if expr="GetFieldType(fl)='number' & GetFieldType(fl2)<>'number'" msg="Типы полей не совпадают."/>

GetExprType

Функция определяет тип результата вычисления выражения в компоненте expr. Возвращаемые значения такие же, как в функции GetFieldType. Если выражение пусто, закомментировано или тип выражения - любой тип, то функция вернет пустую строку. Если в выражении ошибка, то функция вернет '?'.

<if expr="GetFieldType(fl)='number' & GetExprType(expr)<>'number'" msg="Результат выражения не совпадает с типом поля."/>

SameTypes

Функция возвращает истину, если источник и приемник имеют совместимый тип. В качестве источника может использоваться следующие ui-компоненты: field, expr, component, а в качестве приемника: field, component. Функция возвращает результат в зависимости от типа источника и приемника.

Если источником и приемником является поле, то типы полей должны совпадать. Исключением являются типы «число» и «счетчик» - они совместимы. Также тип приемника «текст» совместим с любым типом.

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

Если источником является выражение, а приемником поле или компонент, то тип выражения и поля должны совпадать или быть совместимыми. Тип выражения «число» совместимо с типами полей: объект, счетчик, флажок. Выражение типа «текст» совместимо с типами полей: файл, изображение. Тип выражения любого типа совместим с любым полем или компонентом.

Если в источнике или приемнике не выбрано значение, то функция вернет истину. Тип приемника «текст» совместим с любым типом. Если в источнике или приемника какая-то ошибка, то функция вернет ложь.

Т. к. функция возвращает истину в случае совпадения типов, а в большинстве случаев требуется реагировать как раз на не совпадение, функция применяется с унарной логической операций «Не» - !.

<if expr="!SameTypes(expr, field)" msg="Выражение не совместимо с полем." focus="expr"/>

GetComponentType

Возвращает тип компонента - название класса в нижнем регистре.

<if expt="GetComponentType(cmp)='tdxbutton'" msg="..." focus="cmp"/>

GetTypeText

Функция возвращает название типа, понятное для пользователя. Используется в выражениях атрибута msg.

<if expr="!SameTypes(expr, field)" msg="Выражение типа `GetTypeText(expr)` не совместимо с полем типа `GetTypeText(field)`." focus="expr"/>

ValueIn

Функция возвращает истину, если значение в первом параметре встречается в одном из следующих параметров функции. Эта функция принимает произвольное количество параметров.

<if expr="ValueIn(GetFieldType(field), 'number', 'counter', 'object')" msg="..."/>

Если GetFieldType возвращает одно из значений: number, counter, object, то показать сообщение.

GetValuesCount

Возвращает количество совпадений значения в столбце таблицы. Первый параметр - имя компонента grid, второй - имя компонента в теге grid, третий - значение любого типа. Функция может применяться для проверки наличия определенного значения в таблице, а также для определения дублирования (если результат больше 1).

<ifgrid grid="grid">
  <if expr="GetValuesCount(grid, field, GetText(field))>1" msg="Дублирование поля." focus="field"/>
</ifgrid>

GetRowCount

Возвращает количество строк в таблице.

<if expr="GetRowCount(grid)=0" msg="Добавьте хотя бы одну строку в таблицу." focus="grid"/>

Сопоставление компонентов с параметрами процедуры

Число параметров в процедуре должно совпадать с количеством компонентов, исключая разделители divider. Таблица grid с ее содержимым считается за один параметр.

Каждый параметр должен иметь тип Variant. Параметр для тега grid должен иметь тип TVariantArray2d, который представляет собой двухмерный массив: array of array of Variant. Первое измерение - это строки, второе - столбцы. Параметры и элементы массива могут быть двух типов: LongInt (компоненты number, checkbox, color) и String (остальные). Параметр может быть равен NULL, если компонент был добавлен позже, чем были сохранены параметры.

Вместо Variant для параметров допускается указывать совместимый тип:

  • checkbox - Boolean;
  • color - TColor;
  • number - LongInt, Integer, Byte…;
  • остальные - String.

Новые версии действий

Разработчик может постепенно совершенствовать действия, добавляя новые компоненты. Допускается менять порядок компонентов и столбцов в таблице. Программа сопоставляет компоненты с параметрами по имени компонента. Также допустимо изменять название действия и группу, программа определяет действие по его ID. Вот ID менять нельзя, т. к. тогда все настройки действия могут быть потеряны при открытии окна «Действие».

Действия формы

Действия формы начинают свое выполнение при создании формы. В принципе, на этом этапе их работа может быть закончена. Но это относится только к простейшим действиям, которые, например, устанавливают свойство компонента. Основное же назначение таких действий – подключаться к событиям формы и других компонентов и выполняться при наступлении этих событий. Действие добавляются в свойстве формы «Действия формы».

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

{@action
Id=BE798939-0563-4DC7-8789-BBB636BD45FA
Target=form
OrigName=VisibleByCondition
Name=Видимость компонентов по условию
Group=DEMO
UI=<ui>
  <expr name="condition" caption="Условие" required="1"/>
  <grid name="grid" caption="Компоненты">
    <component name="cmp" required="1"/>
  </grid>
</ui>
Description=Обеспечивает видимость компонентов по условию. Компонент видимый,
если условие истинно. Пример условия:<br><br>
<сode>[дата]<>null</сode><br><br>
Это подключаемое действие.
@}
 
type
  TVCRec = record
    Fm: TdxForm;
    Expr: String;
    Cmps: TVariantArray2d;
    AfterScroll, AfterCancel: TNotifyEvent;
    FieldChange: TFieldChangeEvent;
  end;
 
var
  VCData: array of TVCRec;
  VC_OldDBClose: TNotifyEvent;
 
// Обработчик события закрытия базы данных
procedure VC_DBClose(Sender: TObject);
begin
  SetLength(VCData, 0);
  if VC_OldDBClose <> nil then VC_OldDBClose(Sender);
end;
 
// Поиск нужного элемента массива по форме
function VC_GetIndex(Fm: TObject): Integer;
var
  i: Integer;
begin
  Result := -1;
  for i := 0 to Length(VCData) - 1 do
    if VCData[i].Fm = Fm then
    begin
      Result := i;
      Exit;
    end;
end;
 
// Само действие
procedure VC_SetVisible(var VC: TVCRec);
var
  b: Boolean;
  i: Integer;
  C: TControl;
begin
  // Результат вычисления выражения должен быть логического типа
  b := EvalExpr(VC.Expr, VC.Fm);
  for i := 0 to Length(VC.Cmps) - 1 do
  begin
    // Находим компонент по имени (в Cmps хранятся имена компонентов).
    C := TControl( VC.Fm.FindComponent(VC.Cmps[i][0]) );
    if C <> nil then C.Visible := b;
  end;
end;
 
// Действие при переходе на запись
procedure VC_AfterScroll(Sender: TObject);
var
  VC: TVCRec;
begin
  // Находим наш элемент
  VC := VCData[VC_GetIndex(Sender)];
  // Вызываем старый обработчик события, если он есть
  if VC.AfterScroll <> nil then VC.AfterScroll(Sender);
  // Само действие
  VC_SetVisible(VC);
end;
 
// Действие при отмене изменений записи
procedure VC_AfterCancel(Sender: TObject);
var
  VC: TVCRec;
begin
  VC := VCData[VC_GetIndex(Sender)];
  if VC.AfterCancel <> nil then VC.AfterCancel(Sender);
  VC_SetVisible(VC);
end;
 
// Действие при изменении поля
procedure VC_FieldChange(Sender, Control: TObject; const FieldName: String);
var
  VC: TVCRec;
begin
  VC := VCData[VC_GetIndex(Sender)];
  if VC.FieldChange <> nil then VC.FieldChange(Sender, Control, FieldName);
  VC_SetVisible(VC);
end;
 
// Эту функцию вызывает программа, когда выполняет подключаемое действие.
function VisibleByCondition(aExpr: String; aCmps: TVariantArray2d): Boolean;
var
  i: Integer;
begin
  Result := True;
 
  i := Length(VCData);
  // При первом использовании действия устанавливаем обработчик закрытия базы,
  // чтобы можно было выполнить какие-либо завершающие действия, например,
  // освободить память.
  if i = 0 then
  begin
    VC_OldDBClose := MainWindow.OnDatabaseClose;
    MainWindow.OnDatabaseClose := @VC_DBClose;
  end;
  // Каждый вызов действия увеличивает массив на один элемент.
  SetLength(VCData, i+1);
  // Сохраняем в последний элемент все необходимое для дальнейшей работы действия,
  // подключаемся к событиям.
  with VCData[i] do
  begin
    Fm := Self;
    Expr := aExpr;
    Cmps := aCmps;
    AfterScroll := Self.OnAfterScroll;
    AfterCancel := Self.OnAfterCancel;
    FieldChange := Self.OnFieldChange;
    Self.OnAfterScroll := @VC_AfterScroll;
    Self.OnAfterCancel := @VC_AfterCancel;
    Self.OnFieldChange := @VC_FieldChange;
  end;
end;

Несмотря на относительную сложность, разработка действия формы ведется по шаблону:

1. Создаем структуру для хранения параметров функции, формы, старых обработчиков событий и других данных.

2. Создаем динамический массив для хранения этих структур.

3. При первом использовании действия, устанавливаем обработчик события закрытия базы, предварительно сохранив старый.

4. Увеличиваем размер массива на единицу и записываем в последний элемент необходимые данные.

5. Подключаемся к событиям.

6. Делаем функцию для поиска элемента массива по форме.

7. Создаем необходимые обработчики событий.

8. В обработчиках первым делом ищем нужный элемент массива. Если Sender обработчика не форма, а другой компонент, то добраться до формы можно через свойство Owner компонента или другим способом. В принципе, поиск элемента массива можно делать не по форме, а по другому компоненту.

9. Вызываем старый обработчик события, если он есть.

10. Выполняем необходимые действия.

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

Действия при запуске

Действие выполняется при подключении к базе данных. Этот тип действий разрабатывается по тем же правилам, что и действия формы. Действие может подключаться к событиям разных компонентов и может выполнять свои функции на протяжении всего сеанса работы с БД.

Веб-модули расширений

Начиная с версии 23.5.25 DataExpress поддерживает веб-модули расширений, необходимые для работы расширений в DataExpress WebServer. Это отдельные модули, содержащие код для веб-сервера. Если вы пользуетесь каким-либо расширением в настольной версии программы и хотите, чтобы это расширение работало на веб-сервере, необходимо создать код этого расширения в веб-модуле. В веб-модуле спецификации функций и действий пишутся в сокращенном варианте. Для функций задается параметр Name, для действий - Id:

{@function
Name=Myfunction
@}

{action
Id=345345DF-DFG-345-DFGDFA
@}

По Name и Id ведется поиск функций и действий в модулях расширений. Таким образом, для работы расширений на веб-сервере должны быть установлены оба типа модуля: модуль расширений и веб-модуль расширений.

Нет каких-либо правил именования веб-модулей, но рекомендуется именовать также, как и модули расширений с добавлением суффикса «Web».