Var OldDrawCell: TDrawColumnCellEvent Procedure MyDrawCell(Sender: TObject const Rect: TRect DataCol: Integer Column: TColumn State: TGridDrawState) Begin.


Чтобы посмотреть этот PDF файл с форматированием и разметкой, скачайте его и откройте на своем компьютере.
1


ПрогрТммировТние в

DataExpress 3



Автор: Дуборкин Павел


Редакция:
31
.0
3
.201
8

ОглТвление

Введение

................................
................................
................................
................................
..........................

4

Режим эксперта

................................
................................
................................
................................
...............

5

Обзор редактора скриптов

................................
................................
................................
.............................

6

Поиск в дереве классов

................................
................................
................................
..............................

6

Поиск справки в Интернет

................................
................................
................................
..........................

6

Настройка поиска

................................
................................
................................
................................
........

6

Первое приложение «Привет͕ МИР!»

................................
................................
................................
...........

8

Компоненты
DataExpress

................................
................................
................................
..............................

12

дормы

................................
................................
................................
................................
............................

13

Набор данных

................................
................................
................................
................................
............

14

Модуль формы

................................
................................
................................
................................
..........

15

Обращение к форме

................................
................................
................................
................................
..

15

Обращение к полям формы

................................
................................
................................
.....................

15

Обращение к полю формы через компонент поля

................................
................................
................

16

Обращение к полю «объект» через компонент поля Tdx[ooku
pComboBox

................................
........

17

Обращение к полю «изображение» через компонент Tdx5.Lmage

................................
.....................

17

Обращение к полю «дайл» через компонент TdxCile

................................
................................
............

17

Состо
яния формы

................................
................................
................................
................................
......

18

Изменение͕ сохранение записей и отмена изменений

................................
................................
.........

18

Проверка ввода

................................
................................
................................
................................
.........

18

Добавление записей

................................
................................
................................
................................
.

19

бдаление записей

................................
................................
................................
................................
......

19

Права доступа и блокировка записей
................................
................................
................................
......

19

Переход на запись

................................
................................
................................
................................
.....

20

Открытие набора данных формы

................................
................................
................................
............

21

Закрытие набора данных

................................
................................
................................
..........................

22

Определение количества записей
в форме

................................
................................
............................

22

2


Обновление данных формы

................................
................................
................................
.....................

22

бправление фильтром формы
................................
................................
................................
..................

22

Печать данных формы

................................
................................
................................
..............................

24

Окно редактирования записи

................................
................................
................................
...................

25

Подчиненные формы

................................
................................
................................
................................

27

Обращение к компонентам формы из другого модуля
................................
................................
.........

27

Создание и уничтожение формы в скрипте

................................
................................
............................

27

Параметры формы

................................
................................
................................
................................
....

28

П
редставление формы

................................
................................
................................
................................
..

29

Доступ к представлениям формы в главном окне

................................
................................
.................

29

Создание и закрытие закладки в главном окне приложения

................................
...............................

30

Создание и уничтожение компонента представления формы

................................
.............................

30

Окно списка

................................
................................
................................
................................
....................

31

Создание и уничтожение окна списка

................................
................................
................................
.....

31

бправление окном списка объекта

................................
................................
................................
..........

31

Окно отчета

................................
................................
................................
................................
....................

33

Запросы

................................
................................
................................
................................
..........................

34

Окно редактирования запроса

................................
................................
................................
.................

34

Г
лавное окно приложения
................................
................................
................................
............................

35

Доступ к пунктам меню и кнопкам панелей инструментов

................................
................................
......

36

Стандартные обработчики событий в компонентах

................................
................................
..................

37

Пользовательские окна

................................
................................
................................
................................
.

38

Модуль aain

................................
................................
................................
................................
..................

39

Пользовательские модули
................................
................................
................................
............................

40

SQL
-
запросы

................................
................................
................................
................................
...................

41

Особенности 5X
-
SQL

................................
................................
................................
................................
..

41

Использование Sv[ в скриптах

................................
................................
................................
.................

41

Выполнение произвольных
SQL
-
инструкций

................................
................................
..........................

42

Редактор Sv[
-
выражений

................................
................................
................................
.........................

42

Сводные таблицы͕ таблицы и Sv[
-
запросы

................................
................................
............................

43

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

................................
................................
................................
...............................

44

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

................................
................................
................................
................................
......

44

дункции

................................
................................
................................
................................
......................

44

Действия

................................
................................
................................
................................
.....................

46

3


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

................................
................................
................................
........

46

Атрибуты в тегах

................................
................................
................................
................................
........

47

Таблицы

................................
................................
................................
................................
......................

48

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

................................
................................
.....

49

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

................................
................................
................................
............................

49

Подключаемые действия

................................
................................
................................
..........................

49





4


Введение

Начиная с 5ataExpress 3 beta͕ возможности конструктора существенно расширены благодаря
скриптовому
языку

Pas
cal Script

от компании wemhbject
s

Software
. Pascal Script


это процедурный язык
программирования с поддержкой классов. свляется упрощенным вариантом языка hbject tascal.
Возможности͕ которые дают скрипты:



Реализация сложной

логики͕ автоматическая обработк
а данных.



бправление почти любым компонентом приложения͕ в том числе и созданными автоматически
конструктором (панели инструментов͕ меню͕ строка статуса͕ кнопки͕ окна и т.

д.).



Создание собственных окон и компонентов в режиме выполнения

скрипта.



Подключени
е внешних

библиотек
DLL.



OLE
-
автоматизация.



SQL
-
запросы.

Основное внимание в данном руководстве уделено формам͕ потому что именно формы являются
основными компонентами͕ из которых строится база данных и в которых «крутится» большая часть
логики работы с да
нными.

Для понимания данного материала
желателен

опыт разработки приложений в 5elphi ил
и [azarus͕
знание языка tascal.



5


Режим экспертТ

5ataExpress по
-
прежнему ориентируется на разработч
иков без опыта программирования͕

п
оэтому по
умолчанию редактор скрипто
в и некоторые свойства скрыты. Для доступа к редактору скриптов нужно
включить
режим эксперта
. Включается режим эксперта выбором пункта меню
«
дайл
-
Режим
эксперта
»
.


Рис. 1

На рисунке отмечена кнопка͕ которая открывает редактор скриптов͕ а также дополнител
ьное поле͕
отображаемое только в режиме

эксперта.



6


Обзор редТкторТ скриптов

Редактор скриптов представляет собой отдельное окно͕ которое открывается кнопкой

на панели
инструментов

или нажатием клавиши «
F
4
»
.

На рисунке показано окно редактора скриптов.


Рис. 2

Вверху р
асполагается панель инструментов
. Слева располагается список

модулей
. Посередине


редактор кода. Внизу отображаются сообщения компилятора. Справа находится
дерево классов͕ в
котором

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

Поиск в
дереве клТссов

бстановите фокус на элементе дерева или в поле «Поиск узла» и начните набирать текст. Программа
начнет искать введенный фрагмент текста. итобы найти следующи
й фрагмент͕ нажмите клавишу
«Вниз»͕ чтобы найти предыдущий нажмите клавишу «Вверх».

Поиск спрТвки
в Интернет

К сожалению͕ пока нет возможности создать полноценную справку по всем классам и процедурам. Но
вы можете найти информацию в интернете͕ т. к. !tL ба
зируется на библиотеке [azarus [/[ (аналог
5elphi V/[). Выделите нужный узел и нажмите кнопку «C1». Программа запустит браузер и
автоматически сформирует поисковый запрос. Если выделенный узел является членом класса͕ то в
поисковый запрос добавляется два у
зла: класс и член

класса.

В редакторе кода это тоже работает͕
только там ищется текст͕ который под курсором.

НТстройкТ поискТ

По умолчанию программа ищет справку по узлам в V/[͕ используя поисковик Doogle.
Но͕ скорее всего͕
строка поиска по умолчанию у вас

работать не будет. Вам нужно

использовать свой вариант.

Можно
сделать так. Введите

в поисковике любой запрос

и в строке адреса скопируйте часть
URL
,
которую
7


затем вставьте в окно настройки поиска. итобы открыть настройку поиска в дереве классов в
контекст
ном меню выберите пункт «Настройка поиска».



Рис. 3

Текст поискового запроса формируется очень просто: текст шаблона Uw[ соединяется с текстом
выделенного узла. Пример строки͕ передаваемой браузеру:

https://www.google.ru/search?q=VCL+
TForm
+
CreateNew
.



8


Первое приложение «Привет, МИР!»

Традиционно начнем с простейшего приложения. Кинем на форму кнопку и по нажатию кнопки
покажем сообщение «Привет͕ МИР!».


Рис. 4

Откроем редактор скриптов. Как видите͕ кроме модуля «aain» других модулей не
т. Нет и модуля
ф
ормы «дорма 1»͕

м
одули форм создаются по необходимости. В данном случае такая необходимость
есть. Добавим модуль формы.


Рис. 5

Выберите нужную форму. б нас пока только одна форма͕ так что с выбором проблем не будет.

9


Рис. 6

Модуль формы добавлен. В списк
е отображается имя формы͕ а в скобках имя компонента формы.


Рис. 7

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

procedure

ButtonClick(Sender: TObject);
begin

MsgBox
(„
DataExpress
‟, „
Привет
,
МИР
!!!‟
);

end
;


procedure

Form_Create;

begin

dxButton1.OnClick := @Bu
ttonClick;

end
;

Давайте выйдем из дизайнера и посмотрим͕ что получилось.

10


Рис. 8

А теперь рассмотрим код поподробнее. Программирование в 5ataExpress͕ как и во многих средствах
разработки͕ является событийно
-
ориентированным. В процессе работы приложени
я во
зникают
какие
-
то события (нажатие на кнопку͕ переход на запись͕ открытие окна и т. д.) и разработчик может эти
события обработать͕ т. е. запрограммировать реакцию приложения на то или иное событие. итобы
обработать событие͕ нужно к нему подключиться. Делае
тся это в процедуре Corm_/reate. ото
стандартная процедура͕ которая вызывается конструктором при создании формы.

͙

procedure

Form_Create;

begin

dxButton1.OnClick := @ButtonClick;

end
;

dxButton1


это имя компонента нашей кнопки. иаще всего обращение к ком
поненту осуществляется
через его имя͕ как в данном примере. hn/lick


это свойство компонента͕ которое отв
ечает за событие
нажатия кнопки
,

х
ранит адрес процедуры
-
обработчика события. Адрес процедуры присваивается
свойству через операцию взятия адреса (знач
ок @). В нашем примере


это @.utton/lick.

Сама
процедура
-
обработчик должна находит
ь
ся выше процедуры Corm_/reate. Вот

она
:

procedure

ButtonClick(Sender: TObject);
begin

MsgBox
(„
DataExpress
‟, „
Привет
,
МИР
!!!‟);

end
;


͙

Обратите внимание͕ что процедура име
ет один параметр Sender типа Thbject. Sender указывает на
объект͕ который вызвал процедуру
-
обработчик
а
. В нашем случае Sender = dx.utton1. В зависимости от
типа события у процедур
-
обработчиков может быть разное количество параметров. Свойство hn/lick
имеет

тип TbotifyEvent. Вы можете найти определение этого типа в
дереве классов

в узле Events. Оно
выглядит следующим

образом:

11


Рис. 9



12


Компоненты

DataExpress


Основными компонентами

DataExpress

являются формы͕ представления͕ запросы и
различные
окна

(
редактир
ование
,
списки
,

отчет
ы
)
.

Все компоненты

DataExpress

основан
ы

на классах
Lazarus

LCL

и
FCL
.



Рис. 9а

Синим цветом обозначены классы
LCL
,
а желтым производные

от
LCL

классы
DataExpress
.
Основным
компонентом͕ с которым вы чаще всего будете работать͕ являетс
я форма͕ представленная классом
TdxForm
.



13


Формы

Если вы программировали в 5elphi͕ [azarus или Visual .asic͕ то знаете͕ что формой в этих средах
называется окно Windows. дорма имеет заголовок и кнопки управления. Пример формы показан на
рисунке.

Рис. 10

В

5ataExpress форма является контейнером͕ который может отображаться либо в окне͕ либо в другом
контейнере


например͕
в закладке. В скриптах форма представлена классом TdxCorm͕ который
основан на классе T/ustomtanel. Примеры форм показаны ниже.

Рис. 11

14



Рис. 12

дорма является не просто визуальным компонентом͕ а сложным механизмом͕ который управляет
всеми компонентами на форме. Программа автоматически увязывает компоненты на форме с
данными͕ заполняет списки из справочников͕ отслеживает изменения͕ заполняе
т таблицы и запросы͕
отслеживает изменения в полях и вычисляет выражения͕ и многое
-
многое другое. дорма считывает
записи из базы и хранит в
наборе данных
. Количество записей определяется фильтром формы. Сама
форма может отображать одну запись и записи подч
иненных форм и запросов. Множество записей
формы отображаются в табличной части формы. На рис. 12 табличная часть находится слева от формы.
дормы и табличная часть неразрывно связаны друг с другом. К табличной части формы можно
обратиться через свойство

Gr
id

(класс
TdxGrid
)
.

НТбор
дТнных

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


это записи͕ а столбцы


поля записи
. По
сути͕ в табличной части формы мы видим содержимое набора данных.

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

Т. е. получается͕ что кроме того͕
что компонент сам непосредственно хранит данные͕ еще вдобавок͕ данные хранятся в наборе. Такой
способ хранения
может показаться избыточным͕ но следует учесть͕ что компонент способен хранить
только одно значение͕ а набор данных хранит множество значений.

Кроме этого͕ набор данных знает
какие записи сохранять в базу͕ а какие нет.

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


это указатель на текущую запись. Одновременно изменять можно только одну запись͕ текущую.

Когда
пользователь перемещается по записям͕ происходит смена позиции курсора. Вместе с этим
происходит об
новление содержимого компонентов формы.

Набор данных не имеет соответствующего компонента и отдельного класса. Вместо этого он
15


интегрирован в форму (
а также в запрос
)͕ а управление им осуществляется через методы и свойства
формы.

Примечание.

Для тех͕ кто п
рограммировал в среде
Delphi

или
Lazarus
,
эта технология должна быть
хорошо знакома. В этих средах набор данных представлен базовым классом
TDataset.

Далее в руководстве вы будете встречать фразы «открытие набора данных»͕ «закрытие набора
данных». При отк
рытии набора программа отправляет
sql
-
запрос серверу базы данных и
сохраняет

возвращаемые сервером записи у себя в наборе.

При закрытии происходит очистка и освобождение
памяти
͕ занятая

набором данных
.

Модуль формы

Модуль формы создается по необходимости͕
когда вам нужно написать какой
-
то скрипт͕ работающий
внутри формы. В модуле формы есть две стандартные процедуры͕ которые вызываются программой
при создании и уничтожении формы: Corm_/reate и Corm_5estroy.

В процедуре Corm_/reate вы можете подключиться к с
обытиям формы и ее компонентов͕ а также
выполнить какую
-
либо инициализацию. В этой процедуре обращаться к данным нельзя͕ т. к. они еще
не прочитаны из базы.

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

В мод
уле формы вы можете обращаться к ее компонентам по их именам.

ОбрТщение к форме

Обратиться к форме можно по имени компонента формы͕ например Corm1. Но лучше обращаться к
форме через специальную переменную Self͕ которая всегда указывает на текущую форму в м
одуле.

ОбрТщение к полям формы

Как уже говорилось выше͕ форма интегрирована с набором данных. А компоненты формы связаны с
полями набора данных. дорма имеет свойства͕ которые позволяют читать и записывать в поля набора
данных. Начнем со свойства

Cields. На
пример:

Self.Fields[

Сумма

] := Self.Fields[

Цена

] * Self.Fields[

Количество

];

Вот как обозначено свойство Cields в
дереве классов
:

p
roperty Fields[Name: String]: Variant [rw] default

Свойство является индексным͕ т. е. подобно массиву доступ к элемент
ам свойства осуществляется по
индексу. Только здесь в качестве индекса выступает не число (порядковый
номер
элемент
а

в массиве)͕
а строка͕ имя поля. Тип свойства Variant͕ т. е. может принимать значения любых типов (строки͕ числа͕
даты и т. д.). *rw+ означа
ет͕ что свойство доступно для чтения *r+ и записи *w+. 5efault означает͕ что
свойство является
свойством
по умолчанию͕ т. е. при обращении к свойству
«
Fields
»

можно не
указывать.

Self[

Сумма

] := Self[

Цена

] * Self[

Количество

]
;

Вы можете обращаться не
только к полю формы͕ но и к полю объекта. Вот так:

S := Self[

Клиент|Название

];

Поля объекта можно только читать͕ записывать в них нельзя.

Есть еще несколько свойств͕ упрощающих доступ к полям определенных типов:



AsI[Name: String]: Integer


доступ к чис
ловым полям или объектам. Возвращает целое число.
16


Значение bull преобразуется в

0.



AsF[Name: String]: Extended


доступ к числовым полям. Возвращает вещественное число.
Значение bull преобразуется в

0.



AsDT[Name: String]: TDateTime


доступ к полям даты и
времени. Значение bull преобразуется в

0.



AsS[Name: String]: String


доступ

к

любым

полям
.
Результат возвращается в виде строки.
Значение bull преобразуется в пустую

строку.

Данные свойства только для чтения.

Примечание.

При чтении полей рекомендуется исп
ользовать именно эти свойства͕ а не свойство
Fields
.
Поле может быть пустым (содержать
null
)

и при вычислении выражения может возникнуть ошибка или
получиться неверный результат. Кроме того͕ из
-
за особенностей
Pascal

Script

дробные числа͕
возвращаемые свой
ством
Fields
,

могут восприниматься как целые͕ что может привести к неверным
вычислениям.

Если в полях есть выражения͕ то при изменении поля могут выполняться вычисления в
с
оответствующих полях.

При изменении какого
-
либо поля возникает событие формы hnCiel
d/hange. Вы

можете

обработать

это

событие
.

Пример
:

procedure

MyFieldChange(Sender, Control: TObject;
const

FieldName: String);

begin

if

(FieldName = „
Количество
‟)
or

(FieldName = „
Цена
‟)
then

Self[„
Сумма
‟] := Self.AsI[„
Количество
‟] * Self.AsF(„
Цена
‟)

else

if

Control = dxComboBox1
then


begin



end
;

end
;


procedure

Form_Create;

begin

Self.OnFieldChange := @MyFieldChange;

end
;

В

Form
_
Create

мы

подключаемся

к

событию

hnCield/hange. Тип события TCield/hangeEvent.
Процедура
-
обработчик этого события уже имеет 3

параметра:



Sender


объект͕ в котором произошло событие. бказывает на

форму.



Control


компонент поля͕ которое

изменилось.



FieldName


имя поля͕ которое

изменилось.

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

ОбрТщение к полю формы через компонент поля

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


17


Класс компонента

Тип поля

TdxEdit

Текст

TdxDa
teEdit

Дата

TdxTimeEdit

Время

TdxCalcEdit

иисло

TdxMemo

Заметка

TdxComboBox

Список

TdxLookupComboBox

Объект

TdxObjectField

Поле объекта

TdxCheckBox

длажок

TdxDBImage

Изображение

TdxFile

дайл

Приведенные в таблице dx
-
компоненты͕ кроме Tdx5.Lmage͕
имеют свойство Cield͕ через которое
можно читать и записывать значение поля.

ОбрТщение к полю «объект» через компонент поля Tdx,ookupCombo"ox

С этим компонентом связано два поля. Cield


поле отображающее значение списка (текст в основном)͕
и KeyValue


ID

связанной записи. Если вы напрямую обращаетесь к полям через этот компонент͕ то
вам необходимо присваивать значения обоим полям. Если вы обращаетесь к полю через свойство
Cields формы͕ то нужно присваивать только L5 записи͕ значение списка будет подставле
но
автоматически.

ОбрТщение к полю «изобрТжение» через компонент TdxD")mage

Поле «Изображение» составное и состоит из 4
-
х полей:



само изображение


свойство

Bitmap,



миниатюра


соответствующего свойства

нет͕



файл
-
источник


свойство SourceCilebame͕



имя фай
ла в папке хранения


свойство StoredCilebame


используется͕ если способ хранения «В

папке».

Нельзя обратиться к полю изображения через свойство Cields формы. Обратиться к содержимому
можно через свойство .itmap компонента.
Bitmap

содержит сжатое или раст
янутое изображение
оригинала.
Если попытаться изменить .itmap͕ то изменения не сохранятся в базе. Используйте
[oadCromCile для загрузки изображения из файла в базу. При загрузке изображения все 4 поля
заполняются автоматически. Изменения в поле вызывают со
бытие формы hnCield/hange. Метод
SaveToCile сохраняет содержимое в файл.

ОбрТщение к полю «ФТйл» через компонент Tdx&ile

Поле «дайл» также является составным и также состоит из 4
-
х полей:



описание файла


свойство

Field,

18




сам файл


свойство не предусмотрен
о͕



файл
-
источник


SourceFileName


путь͕ откуда загружен

файл͕



имя файла в папке хранения


свойство StoredCilebame


используется͕ если способ хранения «В

папке».

Нельзя обратиться к полю
файла

через свойство Cields формы. Метод [oadCromCile используется

для
загрузки файла в базу. При загрузке все 4 поля заполняются автоматически. Изменения в поле
вызывают событие формы hnCield/hange. Метод SaveToCile сохраняет содержимое в файл.

Состояния формы

дорма может быть в трех состояниях: состоянии просмотра запи
сей͕ вставки записи и изменения
записи. Исходным состоянием формы является просмотр. бзнать о текущем состоянии можно из
свойства State͕ тип которого T5ataSetState. Свойство может иметь следующие значения:



dsBrowse


состояние просмотра

записей͕



dsInsert


состояние вставки

записи͕



dsEdit


состояние изменения

записи.

Состояние формы может измени
ть пользователь или скрипт͕ выз
вав соответствующий метод формы.

Изменение, сохрТнение
зТписей

и отменТ изменений

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

Self.Edit;

Self[„
Сумма
‟] := 2000;
Self[„
В

резерве

] := 1;
Self.Post;

Метод Edit переводит форму в состояние изменения записи (State = dsEdit). После этого можно
изменять поля
текущей
записи. Метод tost сохраняет изменения записи в базу.

б формы есть свойство hldValues*bame: St
ring+: Variant͕ которое возвращает старое значение поля до
изменения.

Метод Edit вызывает следующие события:



OnBeforeEdit


возникает перед переводом формы в состояние изменения

записи.



OnAfter
Edit


возникает после перевода

формы в состояние изменения

зап
иси.

Метод tost вызывает события:



OnBeforePost


возникает перед сохранением

записи.



OnAfterPost


возникает после сохранения

записи.

Метод /ancel отменяет сделанные изменения в записи. При этом возникают следующие события:



OnBeforeCancel


возникает перед

отменой

изменений.



OnAfterCancel


возникает после отмены

изменений.

ПроверкТ вводТ

П
еред

сохранением

изменений

в окне редактирования

(о нем будет рассказано далее)

возникает

событие
hnValidate. Тип события TValidateEvent. Вот краткий пример обработчи
ка этого

события:

19


procedure

ValidateChanges(Sender: TObject;
var

Ok: Boolean);
begin

Ok

:=
False
;

if

Self
[„
Дата

] =
Null

then

MsgBox(

Ошибка ввода

,

Дата должна быть заполнена

)

else if

Self[„
Деталь

] = Null
then

MsgBox(

Ошибка ввода

,

Деталь не выбрана

)

e
lse

Ok := True;

e
nd
;


procedure

Form_Create;

begin

Self.OnValidate := @ValidateChanges;

end
;

В случае успешной проверки параметру hk присваивается значение True. Если hk = Calse͕ то запись не
сохраняется и форма остается в том же состоянии (вставки или

изменения).

Примечание.
Если запись сохраняется в скрипте методом
Post
͕ то

проверка ввода не осуществляется.
Для выполнения проверки перед сохранением вызовите метод
Validate
.
При вызове этого метода
возникает событие
OnValidate
.

ДобТвление зТписей

Метод

!ppend добавляет новую запись. дорма переводится в состояние вставки записи (State =
dsInsert).

Пример
:

Self.Append;
Self[

Дата

] := Date;

Self[

Статус

] :=

Новая

;
Self.Post;

Тут все почти также как с Edit: после присваивания значений полям с
охраняем изменения в базу.
Метод !ppend вызывает события hn.eforeLnsert


событие до вставки записи͕ и hn!fterLnsert


событие после вставки записи. (Кроме этих событий вызываются еще два͕ о которых пойдет речь ниже:
hn.eforeScroll и hn!fterScroll.) Если !
ppend вызывается в то время͕ когда форма в

состоянии
вставки/изменения͕ то перед вставкой текущая запись сохраняется (неявно вызывается метод tost).
Обратите внимание͕ что проверка ввода при явном и неявном вызове метода
Post

выполнена не
будет
.

УдТление з
Тписей

Метод 5elete удаляет текущую запись из базы вместе с подчиненными данными в подчиненных
формах. Вызывает следующие события: hn.efore5elete


событие до удаления͕ hn!fter



событие после удаления. бдаление может быть выполнено независимо от сос
тояния формы.

ПрТвТ доступТ и блокировкТ зТписей

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

/an!ppend͕ /an5elete и /anEdit͕ которые
возвращают значение типа T!ccessStatus.
Ниже приведены возможные значения͕ возвращаемые
20


методами:

Значение

Методы

Описание

asOk

CanAppend, CanEdit,
CanDelete

Действие (добавление͕ изм
енение͕ удаление) разрешено и
возможно.

asCantAppend

CanAppend

Действие запрещено правами доступа или родительская
форма не находится в состоянии изменения или вставки.

asCantEdit

CanEdit

Действие запрещено правами доступа или родительская
форма не наход
ится в состоянии изменения или вставки.


CanDelete

Действие запрещено правами доступа или родительская
форма не находится в состоянии изменения или вставки.

asModified


З
апись была изменена другим пользователем. Программа
бы

в этом случае сообщила об этом пользователю и
предложила обновить данные. В скрипте же решение за
вами.

Желательно обновить данные͕ потому что изменения
могут повлиять на право изменения или удаления записи.



З
апись был
а удале
на другим пользователем.

asLocked


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

asHasRef

CanDelete

На запись есть ссылки в других формах͕ удалить нельзя.

Вышеуказанные методы необязательно вызывать перед изме
нением или удалением записи. Методы
Append
,
Edit

и

сами вызывают методы
CanAppend
,
CanEdit

и
CanDelete
͕ чтобы определить
возможность
добавления͕
изменения или удаления записи. В случае успеха возвращается
asOk
.

Примечание.

Надо заметить͕ что
Append
,

Edit

и

выполнятся успешно͕ даже если изменение и
удаление ограничено правами доступа.

Если данные действия нельзя выполнять по условию доступа͕
то вызовите
CanAppend
,
CanEdit

или
CanDelete

перед операцией
.

Методы могут вернуть
asCantAppend
,
asCant
Edit

и
asCantDelete

и в том случае͕ когда действие
разрешено правами доступа. Такой результат получится͕ если попытаться совершить операцию в
подчиненной форме в то время͕ когда родительская форма не находится в состоянии
редактирования/вставки.

Метод Edit

блокирует запись для остальных пользователей при многопользовательском доступе к
базе. Методы tost и /ancel снимают блокировку. Ошибки в коде могут привести к зависшим
блокировкам͕ если ошибка возникла между Edit и tost//ancel. Однако блокировка автоматич
ески
снимается простым перезапуском программы.

Переход нТ зТпись

Для перехода на определенную запись используются следующие методы:



MoveFirst, MoveLast, MoveNext, MovePrior


переход соответственно на первую͕ последнюю͕
следующую͕ предыдущую

записи.



MoveBy
(Distance: Integer)


перемещение на 5istance записей вперед или назад (если значение
отрицательное.

21




MoveTo(RecNo: Integer)


переход на запись по
д

номером

RecNo.



GotoRecord(RecId: Integer)


переход

на

запись

с

Id =

RecId.



Locate(const FieldName: String;
FieldValue: Variant; Options: TLocateOptions)


переход

на

запись

с

определенным

значением

поля

(FieldName = FieldValue). Options


опции

поиска
.
loCaseInsensitive


поиск

без

учета

регистра
, loPartialKey


искать

фрагмент

текста
.

Во время перехода возника
ют следующие события: hn.eforeScroll


событие до перехода на запись͕
OnAfterSc
r
oll


событие после перехода на запись. Если запись находится в состоянии
вставки/изменения͕ то перед переходом запись сохраняется͕ т. е. неявно вызывается метод tost.

С метода
ми
перехода
связаны еще два метода͕ которые также используются при перемещении


это
.hC и EhC. .hC возвращает True͕ если достигнуто начало
набора данных
. EhC возвращает True͕ если
достигнут конец

набора данных
.



Self.DisableControls;

Self.DisableScrollEv
ents;

Self.MoveFirst;

w
hile not

Self.Eof
do

b
egin

// Выполняем какие
-
то действия



Self
.
MoveNext
;

e
nd
;

Self.EnableControls;

Self.EnableScrollEvents;

Пример показывает прохождение по всем записям формы. Для ускорения обработки отключается
связь визуальных
компонентов с набором данных (
DisableControls
)
͕ а также отключается реакция на
события
OnBeforeScroll

и
OnAfterScroll

(
DisableScrollEvents
)
,
в том числе штатная обработка
(обновление подчиненных форм͕ запросов͕ вычисление надписей и т. д.).

После обработки

данных
связь нужно включить (
EnableControls
,
EnableScrollEvents
).

Открытие

нТбор
Т

дТнных

формы

Если форма создается программой͕ то
набор данных открывается

автоматически. Если форма
создается в скрипте͕ то
открывать

надо самостоятельно. Для этого можно во
спользоваться одним из
следующих методов: hpen͕ hpenwecord и hpenwecords.

Open


загружает данные так
,

как это делает программа. Если предустановки фильтра не определены͕
то загружаются все данные͕ иначе


набор записей определяется предустановкой фильтра͕

находящейся первой в списке предустановок (см. свойство формы «Предустановки фильтра»).

OpenRecord(RecId: Integer)


загружает одну запись с определенным Ld.

Используется также для
добавления записей
:

Fm

:=
TdxForm
.
Create
(„
Заявки
‟);

Fm
.
OpenRecord
(0);


//
Открываем пустой набор данных для добавления записей

Fm.Append;



Fm.Post;



Вместо 0 может быть любо
й несуществующий
ID

записи.

22


OpenRecords(const Filter: String; SelectCondition: Boolean)


загружает

набор

записей
,
определенный

фильтром
.
Синтаксис фильтр
а такой же͕ как синтаксис условия отбора записей в настройках прав
доступа͕ а

именно:

[имя поля формы]<операция сравнения><выражение>

Имя поля формы указывается в квадратных скобках. Операция сравнения: =|<>|<|<=|>|>=|==|#.
Выражение


полноценное выражени
е. В таком выражении нельзя обращаться к полям формы͕ т. к.
форма для этого выражения просто
-
напросто не определена. Пример:

Self
.
OpenRecords
(„[
Дата
�]=
cdate
(“02.03.2016”) & [
Дата
]=
Date
‟,
False
)

Если выражение содержит знаки & или |͕ то выражение берется
в скобки:

Self.OpenRecords(

[название]=(“Tom & Jerry”) | [название]=”Ну, погоди!”

, True)

Второй параметр определяет͕ будет ли учитываться условие отбора͕ заданное для этой формы в
настройках роли. True


условие отбора учитывается͕ т. е. к указанному фил
ьтру будет добавляться
(операцией !b5) условие отбора. Более подробную информацию об условии отбора читайте в справке
в разделе «
бправление

доступ
ом
-
бсловие отбора».

Методы вызывают следующие события: hn.eforehpen


событие до чтения записей͕ hn!fterhpen



событие после считывания записей. После чтения вызывается событие hn!fterScroll даже если
нет
записей
.

ЗТкрытие
нТборТ дТнных

Набор данных

закрывается методом /lose. Обычно это необходимо делать͕ когда вы создаете форму в
скрипте͕ чтобы освободить занятую

оперативную память. Метод вызывает события hn.efore/lose

-

событие до закрытия
набора данных
, OnAfterClose


событие после закрытия

набора данных
.

Примечание.

При уничтожении формы методом
Free
,
закрытие набора данных производится
автоматически.

Определе
ние количествТ зТписей в форме

Метод wecord/ount возвращает количество загруженных в набор данных записей. Однако стоит иметь
в

виду͕ что данные загружаются из базы не все͕ а порциями по мере надобности. Таким образом сразу
после загрузки данных wecord/oun
t может вернут͕ к примеру͕ 20 записей. Но при переходе на 20
-
ю
запись подгружается еще порция данных͕ получается уже 40͕ и т. д. итобы определить реальное
количество загружаемых записей͕ нужно вызвать метод aove[ast. Метод aove[ast способствует
загрузке вс
его набора записей.

Обновление дТнных формы

Метод wefresh обновляет данные формы. Она последовательно вызывает /lose и hpen (!). ото значит͕
что если вы программно читаете данные методами hpenwecord или hpenwecords͕ то wefresh вызывать
нельзя͕ т. к. будет
вызван метод hpen.

УпрТвление фильтром формы

дильтром формы можно управлять с помощью свойства
Filter

класса

TFilterObject
.

Пример
настройки
фильтра
:



23


v
ar

FF
:
TFilterField
;

begin

Self
.
Filter
.
Clear
;




//
Удаляем

все

поля

из

фильтра

FF

:=
Self
.
Filter
.
AddFiel
d
(„
Количество
‟);

//
Добавляем

поле

фильтра

FF
.
Values
.
Add
(„2 ..
5‟);


//
Для

чисел
,
дат

и

времени

значение задается как диапазон

FF
.
Values
.
Add
(„10 ..
‟);


//
Если нижней или верхней границы нет, то ставится пробел

FF := Self.Filter.AddField(„
Название
‟);

FF.
Values.Add(„
Мука
‟);

FF
.
IsNot

:=
True
;




//
Ищем

все
,
кроме

муки

FF

:=
Self
.
Filter
.
AddField
(„
Клиент
‟);

// Если добавляем объект,

FF
.
Values
.
Add
(
ID

записи

)
;


//
то значением должно быть
id

записи
, число
.

Self.Refresh;

end
;

дильтром можно управлять до и п
осле открытия набора данных. Пример чтения фильтра:

var

FF: TFilterField;

begin

FF := Self.Filter.FindField(„
Количество
‟);

if

�FF.Values.Count 0
then

begin

Debug(FF.Value[0]);

Debug(FF.EndValue[0]);

end
;

end
;

Краткое описание

метод
ов

и свойств фильтра

TF
ilterObject
:

function AddField(const FieldName: String): TFilterField

Метод добавляет поле в фильтр.

procedure

Clear

Метод удаляет все поля из фильтра.

procedure

(
F
:
TFilterField
)

Метод удаляет из фильтра поле. В качестве параметра передается
объект поля фильтра.

function FindField(const FieldName: String): TFilterField

Ищет в фильтре поле с указанным именем и возвращает объект поля. Если объект не найден͕
возвращает
nil
.

property

Count
:
Integer

[
r
]

Возвращает количество полей в фильтре.

pro
perty Fields[Index: Integer]: TFilterField [r] default

Доступ к полю фильтра по индексу. ото свойство по умолчанию͕ т. е. название свойства можно не
писать:
Self
.
Filter
[1].
Value

:= ͙




24


Краткое описание свойств поля фильтра

TFilterField
:

Свойство

Описание

p
roperty

FieldName
:
String

[
r
]

Имя

поля
.

property IsNot: Boolean [rw]

длажок

«
Не
».

property IsNull: Boolean [rw]

длажок «Пусто».

property Values: TStringList [r]

Доступ к значениям поля фильтра.

property Value[Index: Integer]: String [r]

Доступ к значен
ию поля

или к начальному значению͕
если это
диапазон

(число͕ дата͕

время
).

property EndValue[Index: Integer]: String [r]

Доступ к конечному значению диапазона.

ПечТть дТнных формы

Печать данных осуществляется методом trint:

Print
(
const

TemplateName
,
OutF
ileName
:
String;
var

Errs: String; OpenFile: Boolean
)

Описание параметров:



TemplateName


путь к файлу шаблона. Может быть абсолютным и относительным. Если указан
относительный путь͕ то используется папка шаблонов (указывается в настройках программы).



Out
FileName


абсолютный путь к выходному файлу. Если указана пустая строка͕ то путь
определяется

программой.



Errs


сюда записываются возможные ошибки при

печати.



OpenFile


если True͕ то программа открывает сформированный документ в текстовом
редакторе.

Pri
nt вызывает событи
е
OnPrint
:

TPrintEvent =
procedure

(Sender: TObject; Action: TPrintActionType;
const

SourceName,
FieldName: String;
var

Value: String;
var

Accept: Boolean)

бстановив

обработчик события͕ вы можете влиять на процесс печати.

В параметр
Acti
on

передается
действие͕ которое выполняет программа

во время печати
.

Возможны следующие значения:

Значение

Описание

paBeginPrint

Начало печати. Параметр Sourcebame содержит полный путь к файлу шаблона.
В этот момент вы можете выполнить какие
-
то подготовит
ельные действия.
Параметр !ccept игнорируется.

paBeginData

Начало данных. Данное действие соответствует тому͕ когда программа
впервые встречает тег form или grid. В этот момент программа переводит
курсор набора данных на первую запись
-

это действие по ум
олчанию͕ если
параметр !ccept равен Calse. Вы можете перехватить это действие͕ установив
!ccept в True. В скрипте вы можете͕ к примеру͕ позиционировать курсор на
первой записи своего набора данных.


Параметр Sourcebame содержит имя источника данных͕ указан
ного в теге
form/grid. ото может быть имя формы͕ запроса или произвольное имя.

25


paNextData

Следующая запись. Когда программа встречает тег end͕ она перемещает курсор
набора данных на следующую запись и повторяет часть шаблона между тегами
form
-
end или grid
-
end. Если достигнут конец записей͕ то программа переходит к
участку шаблона за тегом end. Перемещение курсора
-

это действие по
умолчанию͕ если !ccept равен Calse. бстановите !ccept в True͕ если хотите
перехватить это действие. Например͕ вы можете перейти

к следующему
элементу массива данных или переместить курсор на следующую запись. Когда
достигните конца данных͕ то установите !ccept в Calse͕ чтобы программа
продолжила печать шаблона за тегом end.


Параметр Sourcebame содержит имя источника данных͕ указа
нного в теге
form/grid. ото может быть имя формы͕ запроса или произвольное имя.

paPrintField

Печать поля. Sourcebame
-

имя источника данных͕ Cieldbame
-

имя поля. Если
!ccept равен True͕ то значение поля будет вычислять скрипт͕ передавая Value в
шаблон. Е
сли !ccept равен Calse͕ то программа сама будет вычислять поле
штатными средствами.

paEndPrint

Конец печати. дайл документа уже сформирован. Вы можете выполнить какие
-
то завершающее действия͕ например освобождение памяти. Параметр !ccept
игнорируется
.


Примечание:

1.

Действия
paBeginData
,
paNextData

обычно перехватываются͕ когда надо распечатать набора
данных͕ например
TdxSQLQuery

или произвольный массив.

2.

В обработчик
е

параметр
Accept

передается со значением
False
.
Не меняйте его͕ если действие
должно быть
обработано самой программой.

3.

Значение в теге group обрабатывается как печать поля patrintCield.

Окно редТктировТния зТписи

С формой может быть связано окно редактирования записи. Доступно через свойство EditWindow͕ если
представление формы «Только таблица
»

или форма подчиненная
. В противном случае EditWindow =
nil. Программа автоматически создает необходимые компоненты окна и помещает форму в окно.

26


Рис. 13

Окно редактирования представлено классом TEditWindow. окземпляр окна сам по себе создавать
нельзя͕ т
. к. окно тесно связано с формой. На рисунке показано
,

из каких компонентов состоит окно.
Компоненты доступны через следующие свойства класса:



ScrollBox: TScrollBox


контейнер
,

в который помещается форма. Если форма не помещается
полностью в контейнер͕ то

появляются полосы

прокрутки.



Form: TdxForm


сама форма.



Buttons: TButtonPanel


панель кнопок.

Окно может быть показано в результате действий пользователя͕ когда тот
,

например
,

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

procedure

AnyButtonClick(Sender: TObject);
begin

Self.Append;

Self[

Дата
‟] := D
ate;

if

Self.EditWindow.ShowModal = mrOk
then

Self.Post

else

Self.Cancel;

end
;

Перед закрытием окна͕ про
грамма проверяет правильность ввода данных и
возникает

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

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


27


Подчиненные формы

Подчиненные формы не являются самостоятельными
компонентами

и всегд
а создаются вместе с
родительской формой. Они являются частью механизма формы. Они также могут иметь свой модуль.
Модуль подчиненной формы не может существовать без модуля родительской формы. И если при
добавлении модуля подчиненной формы͕ модуля родительс
кой формы нет͕ то он создается
автоматически.

Подчиненные формы того же типа͕ что и родительские͕ т. е. TdxCorm. Обратиться к подчиненной
форме из родительской можно либо по имени компонента формы͕ либо по ее имени через свойство
Forms:

procedure

AppendBnC
lick(Sender: TObject);
begin

i
f

�(Self.State dsInsert)
and

�(Self.State dsEdit)
and

(Self.
Edit = asOk)
then

with

Self.Forms[„
товары

]
do

b
egin

Append;

Fields[

Количество

] := 1;

i
f

E
ditWindow.ShowModal = mrOk
then

Post

e
lse

Cancel;

e
nd
;

e
nd
;


Обратите

внимание на первую строчку в обработчике (Lf ͙). Родительская форма должна находит
ь
ся в
состоянии изменения записи͕ если в подчиненных формах происходит манипулирование записями. В
противном случае
вы не сможете добавить запись (
Append

вернет
asCantAppend
)
.

Изменения в
подчиненных формах не сразу попадают в базу͕ а только после того как сохранится родительская
запись.

б подчиненных форм есть некоторые ограничения на вызов методов. Нельзя

вызывать

следующие

методы
: Open, OpenRecord, OpenRecords, Close, Pri
nt.
Вызов этих методов будет приводить к

ошибке.

ОбрТщение к компонентТм формы из другого модуля

К сожалению ограничения tascal Script не позволяют обратиться к компоненту формы по его имени
через точку:

Self.Forms[„…‟
].dxEdit1.Color := clRed;

отот код ра
ботать не будет. Для доступа к компоненту можно воспользоваться методом
FindComponent:

TdxEdit(Self.Forms[„…‟].FindComponent(„dxEdit1‟
)).Color := clRed;

СоздТние и уничтожение формы в скрипте

дорма

создается

к
онструктор
ом

класса
TdxForm
:

constructor

Creat
e
(
const

FormName: String)
;

Конструктор

имеет единственный параметр: Cormbame


имя формы. дорма͕ созданная таким
образом
,

имеет представление «Только таблица» независимо от того͕ что было задано в дизайнере.
28


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


все работает.

После создания формы нужно прочитать данные из базы методами hpen͕ hpenwecord или
hpenwecords. Такую форму можно использовать для какой
-
ли
бо скрытой обработки данных͕ печати͕
редактирования записей и т. д.

дорма уничтожается методом
Free
.
При уничтожении͕ если набор данных не был закрыт͕ он
закрывается автоматически.

ПТрТметры формы

Параметры используются для передачи сведений форме из друго
го модуля͕ для временного хранения
значений͕ выполнения какого
-
либо действия. Параметры доступны через свойство tarams класса
Ttaram[ist. Доступ к параметрам осуществляется по им
ени. Параметр может хранить

значение типа
Variant и объект Thbject. Если при
присваивании значения параметру его нет в списке͕ то он
добавляется автоматически. Если при чтении параметр не находится͕ то возвращается bull или nil.
Пример обращения к параметру:

Fm.Params[„
Статус

].Value := 3;
Self.Pa
rams[„
Объект

].Object := AnyObj;

К
огда присваивается значение параметру͕ возникает событие hnSettaram:

TParamNotifyEvent =
procedure
(Sender: TObject;
const

ParamName: String);

hnDettaram возникает͕ когда читается значение параметра. Подключив обработчики к этим событиям
можно имитировать
«свойства» классов. Т. е. при присваивании или чтении значения выполнять какие
-
нибудь действия

внутри формы
.

Пример:

procedure

const

ParamName: String);

begin

if

ParamName = „
тест

then

begin

//
Какие
-
то действия

end
;

end
;


procedure

Form_Create;

begin


end
;

В другом модуле:



//
Присваивание параметру значения вызовет в форме какие
-
то действия

Fm
.
Params
.
Values
[„тест‟] := 1;






29


ПредстТвление
формы

Представлением формы
называется положе
ние формы͕

табличной части

и дерева

относительно друг
друга. На рис. 14 показано представление формы «Таблица сверху». За представление формы отвечает
компонент класса TCormView. Компонент TCormView является контейнером.


Рис. 14

Для доступа к компонентам

используются следующие свойства:



Form


собственно форма͕



Grid


табличная часть

формы͕



Tree


дерево͕ если оно

есть͕



ScrollBox


контейнер͕ в котором располагается

форма͕



TreeSplitter, FormSplitter


сплиттеры.

Компоненты создаются вне зависимости
,

отобр
аж
аются

они или нет.

Доступ к предстТвлениям формы в глТвном окне

Главное окно доступно через переменную aainWindow. Компоненты представления формы
располагаются в закладках. Закладки доступны через свойство tages. Представления формы доступны
через свойст
во CormViews:

property

FormViews[Index: Integer]: TFormView [r]

Пример
:

MainWindow.FormViews[MainWindow.Pages.TabIndex].Form.MoveNext;

30


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

СоздТние и зТкрытие зТклТдки в глТвном окне приложения

Закладка создается при помощи метода главного окна /reatetage:

function

CreatePage(
const


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

Пример:

Tb := MainWindow.CreatePage(„
Дела

, vtGridLeft);

// При указании активной закладки, данные читаются из базы автоматически
MainWindow.Pages.ActivePage := Tb;

Закрывается

закладка

методом

DestroyPage:

procedure

DestroyPage(Page

СоздТние и уничтожение компонентТ предстТвления формы

Компонент

создается

конструктором

Create
:

constructor

Create
(AOwner: TComponent;
const

FormName: String; ViewType: TViewType)



AOwner


компонент
-
владелец͕



FormName


имя

формы͕



ViewType


представление

формы.

Возможны следующие значения:
vtGridTop



таблица вверху͕
vtGridBottom



таблица внизу͕
vtGridLeft



таблица слева͕
vtGridRight



таблица справа͕
vtGridOnly



только табличная часть

(
форма находится в окне редактирования)͕
vtWithoutGr
id



только форма͕
vtSimpleForm



простая форма͕
vtDefault



значение͕ установленное в дизайнере.

Обычно нет необходимости создавать этот компонент͕ если только вам не нужно создать к
акое
-

нибудь нестандартное окно или несколько представлений в одном окне.

Если владелец не указан (!hwner = nil)͕ то уничтожать компонент надо самостоятельно. Для этого
вызывается метод Cree.



31


Окно спискТ

Еще одним элементом интерфейса 5ataExpress является окно списка. Оно открывается при нажатии на
кнопку объекта. Представлен
о классом T[istWindow.


Рис. 15

Доступ к компонентам можно получить через следующие свойства:



ToolBar


панель

инструментов͕



FormView


компонент представления

формы͕



Buttons


панель

кнопок.

СоздТние и уничтожение окнТ спискТ

Окно списка вполне может сущ
ествовать самостоятельно без привязки к полю
типа
«
объект
».
Для

этого

нужен

конструктор

Create
:

constructor

Create
(
const

FormName: String; ViewType: TViewType)
;

Параметры
:



FormName


имя формы. Не допускается указывать дочерние

формы.



ViewType


представл
ение формы: vtDridTop


таблица сверху͕ vtDrid.ottom


таблица внизу͕
vtGridLeft


таблица слева͕ vtDridwight


таблица справа͕ vtDridhnly


только таблица͕
vtWithoutGrid


только формы͕ vtSimpleCorm


простая форма͕ vt5efault


представление по
умолчанию͕

заданное в

дизайнере.

Пример:

ListWnd := TListWindow.Create(„
Клиенты
‟, vtGridLeft);

ListWnd
.
Form
.
Open
;

// Разработчик должен самостоятельно открывать набор данных

ListWnd
.
ShowModal
;

ListWnd.Form.Close; // … и закрывать

(необязательно, если окно уничтожае
тся)

ListWnd.Free;


// Уничтожение окна

списка

УпрТвление окном спискТ объектТ

Для управления окном списка объекта надо подключиться к событию объекта
OnCreate
ListWindow
.
32


Пример:

p
rocedure

ListWindowCreate(Sender: TObject; aWindow: TForm);

var

LWnd: TList
Window;

b
egin

LWnd := TListWindow(aWindow);

LWnd.FormView.
F
orm
.EditWindow.OnShow := @EditWindowShow;

LWnd.Caption := „…‟;

e
nd
;


procedure

Form_Create;

begin

dxLookupComboBox1.OnCreateListWindow := @ListWindowCreate;

end
;




33


Окно отчетТ

Все отчеты 5ataExpr
ess открываются в окне класса TweportWindow.

Рис. 16

Окно состоит из следующих компонентов:



ToolBar


панель

инструментов͕



Filter


фильтр͕



FilterSplitter


сплиттер͕



QGrid


компонент

запроса͕



StatusBar


строка

статуса.

Некоторые компоненты могут быть с
крыты в зависимости от настроек отчета. Пример
:

p
rocedure

ButtonClick(Sender: TObject)

v
ar

RpWnd: TReportWindow;

b
egin

RpWnd := TReportWindow.Create;

RpWnd
.
ShowReport
(

Прибыль

за

период

);

RpWnd.Free;

e
nd
;

Окно с
оздается конструктором /reate
.
Набор данных

запроса открывается и закрывается
автоматически.



34


ЗТпросы

Запросы представлены компонентом TdxvueryDrid. Большинство методов и свойств этого компонента
аналогичны методам и свойствам формы (TdxCorm) и табличной части формы

(TdxDrid). Вы не можете
повлият
ь на результат вывода запроса (состав полей͕ фильтры). Вы можете только читать и обновлять

данные.

Окно редТктировТния зТпросТ

Если быть более точным͕ то это окно редактирования формы͕ связанной с запросом. Если запрос
редактируемый͕ то с ним связано окно
редактирования. Окно редактирования создается динамически
при первой попытке редактировать данные͕ которое инициируется командами

«Добавить»͕
«Изменить» и «бдалить» (!). При этом возникает событие hn/reateCorm:

TCreateFormEvent =
procedure
(Sender: TObject;

Form: TdxForm);

Параметр Corm как раз указывает на созданную форму.

Пример

кода
:

procedure

QueryForm
Create
(Sender: TObject; Fm
: T
dx
Form);

begin

Fm
.EditWindow.OnShow := @EditWindowShow;

end
;


procedure

Form_Create;

begin

dxQueryGrid1.OnCreateForm := @Quer
yFormCreate;

end
;




35


ГлТвное окно приложения

Главное окно приложения доступно через переменную aainWindow. Класс окна TaainCm.

Рис. 17

Главное окно может перехватывать события создания и уничтожения формы͕ создания окон списков и
отчетов.

Для этого служа
т следующие свойства:

OnCreateForm, OnDestroyForm:
TCreateFormEvent =
procedure
(Sender: TObject; Form: TdxForm);

OnCreateListWindow =
procedure

(Sender: TObject; aWindow: TForm);

OnCreateReportWindow =
procedure

(Sender: TObject; aWindow: TForm);

Таким
образом͕ вы можете выполнить какие
-
либо действия общие для всех компонентов базы.



36


Доступ к пунктТм меню и кнопкТм пТнелей инструментов

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

или изменить стандартное поведение
. Не сказать͕ что в этом есть прям такая
необходимость͕ но возможность есть. Доступ к элементам осуществляется по индексам.

Например:

proc
edure

NewHandler(Sender: TObject);

begin

//
Какие
-
то

действия



if

�OldHandler
nil

then

OldHandler(Sender);

end
;


procedure

Form_Create;

begin

OldHandler := Self.Grid.PopupMenu.Items[0].OnClick;

Self.Grid.PopupMenu.Items[0].OnClick := @NewHandler;

end
;

В примере подменяем стандартный обработчик события на свой. При необходимости вызываем
старый обработчик. Однако желательно использовать в качестве индекса не число͕ а константу. Все
возможные константы для разных элементов интерфейса вы можете найти в
дер
еве классов

в

подразделах

«aain

menu

items»͕

«topup

menu

items»͕

«Toolbar

buttons»

раздела

«
Constants
».
Пример
:

MainWindow.ToolBar.Buttons[TBN_APPEND].Caption := „
Добавить

запись
';

Также не вставляйте пункты меню между стандартными пунктами͕ т. к. это мо
жет привести к ошибкам.
Добавляйте их в конец меню.



37


СтТндТртные обрТботчики событий в компонентТх

Для обеспечения нужного функционала некоторые события компонентов уже имеют обработчики.
Например͕ событие табличной части hn5raw/olumn/ell используйте для
раскраски и вывода миниатюр
изображений. Если вы хотите добавить дополнительный функционал͕ то можете подменить
стандартный обработчик на свой͕ предварительно сохранив старый в переменной. А в своем
обработчике уже вызываете стандартный обработчик.

Пример:

v
ar

OldDrawCell: TDrawColumnCellEvent;


p
rocedure

MyDrawCell(Sender: TObject;
const

Rect: TRect;
DataCol: Integer; Column:

TColumn; State: TGridDrawState);

b
egin

//
Вызываем

старый

обработчик

OldDrawCell(Sender, Rect, DataCol, Column, State);

//

i
f

TdxGri
d(
Sender).GetFieldName(Column) = „
Количество


then


b
egin

if

Self.AsI
[

Количество

] 0 then TdxGrid(Sender).Canvas.Brush.Color := clRed;

e
nd
;

e
nd
;


p
rocedure

Form_Create;

b
egin

OldDrawCell := Self.Grid.OnDrawColumnCell;

Self.Grid.OnDrawColumnCell := @MyD
rawCell
;

e
nd
;

В данном примере раскрашиваем ячейки колонки «Количес
тво» с отрицательным значением.

Ниже приведены компоненты и события͕ которые заняты программой.

Компонент

События

TdxGrid

OnCellClick, OnDblClick, OnDrawColumnCell, OnKeyDown

TdxLookupCo
mboBox

Button.OnClick

TdxCalcEdit, TdxDateEdit,
TdxTimeEdit,
TdxMemo

Button.OnClick

TdxQueryGrid

OnDblClick, OnDrawColumnCell

PopupMenu

OnPopup




38


ПользовТтельские окнТ

Вы можете создавать окна динамически для каких
-
либо специфических задач. Вам доступ
ны
компоненты͕ не связанные с данными: TEdit͕ T[abel͕ T/ombo.ox͕ TSpeed.utton и т. д. Пример:

MyWnd := TWindow.Create
;
MyWnd.Width := 300;

MyWnd.Height := 200;

Bn := TBitBtn.Create(MyWnd);
Bn.Parent := MyWnd;

Bn.Caption := „
Нажми

;
Bn.OnClick := @
ClickHandler;
MyWnd.ShowModal;

MyWnd.Free;




39


Модуль Main

Модуль aain является стандартным модулем͕ который создается автоматически и не может быть
удален. Основное назначение модуля обработка событий открытия и закрытия базы данных
. События
обрабатываются с
тандартными процедурами модуля
D
atabase_
O
pen и

D
atabase_
C
lose.

procedure

Database_Open;
begin

MainWindow.OnCreateForm := @FormCreate;

//
какие
-
нибудь

действия

end
;


procedure

Database_Close;
begin

//
завершающие

действия

e
nd
;




40


ПользовТтельские модули

Пользовательские модули являются относительно самостоятельными участками кода. Они могут
содержать часто используемые процедуры͕ функции͕ определения типов͕ константы. Назначение
модулей целиком определяется разработчиком. Модули по
дключа
ются директивой препроцессора $
I
.

{$I mymodule}


procedure

MyModuleProc(…);
begin



e
nd
;

Перед компиляцией препроцессор анализирует скрипт и вместо директив вставляет исходный код
подключаемого модуля. Получается͕ что код скрипта и код модуля объед
иняются в одно целое. Потом
все это компилируется.

Пользовательские модули не используются самостоятельно͕ как модули форм и модуль aain͕ поэтому
не компилируются. ото значит͕ что если в коде модуля есть ошибка͕ то компилятор ее обнаружит
только тогда͕ ког
да этот модуль будет подключен в модуле формы или модуле aain.

Модуль aain тоже можно подключать в модулях форм.



41


SQL
-
зТпросы

Синтаксис Sv[
-
выражений в 5ataExpress (5X
-
Sv[) почти такой же͕ как в Cirebird
-
Sv[. Пример:

select

t.id, t.[
номер
]
as

num, t.[
дата
]
as

data, [
клиенты
].[
название
]
as

client

f
rom

[продажа товара] t
inner join

[клиенты]
on

t.[клиент]=[клиенты].id

o
rder by

t.[дата]

Отличительной особенностью 5X
-
Sv[ является чередование названий форм и полей форм с
названиями таблиц и полей базы данных.
Названия форм и полей форм пишутся в квадратных скобках.
В данном случае форма является аналогом таблицы.

Особенности DX
-
SQL

Перед тем как сделать запрос программа подменяет названия форм и полей в квадратных скобках на
системные имена таблиц и полей. Если

перед именем поля указан псевдоним или форма͕ то
программа может точно определить к какой форме относится поле и если не находит его͕ то выдает
сообщение об ошибке. Если псевдоним или форма не указана͕ то программа пытается его найти во
всех формах͕ переч
исленных в секции «Cwha». При этом если поле не находится͕ то ошибка не
появляется. Однако сервер выдаст сообщение об ошибке. Поэтому старайтесь указывать имена полей
вместе с именем формы или псевдонимом. Обязательно пишите перед именем поля псевдоним или

имя формы͕ если в имени поля есть точки.

Не используйте в качестве псевдонимов названия типа f1͕ f2͕ t1͕ t2͕ т. к. они могут совпасть с
названиями полей и таблиц в базе данных. Используйте в псевдонимах только символы латинского
алфавита͕ подчеркивание и
цифры.

При создании формы автоматические создается системное поле «id»͕ которое является первичным
ключом таблицы. При создании подчиненной формы дополнительно создается системное поле «pid»͕
которое является внешним ключом и ссылается на id родительской

ф
ормы.

ИспользовТние 31, в скриптТх

Для работы с Sv[ используйте класс TdxSv[vuery и функцию
SQLSelect:

function

SQLSelect(
const

SQL: String): TdxSQLQuery

Класс TdxSv[vuery содержит почти тот же набор методов и свойств͕ что и форма. Пример
:

with

SQLSelect(

select id, [
название
] from [
запчасти
] order by [
название
]

)
do

begin

while not

EOF
do


begin

//
Какие
-
то

действия



MoveNext;

end
;

Free;

end
;

Кроме выборки данных класс умеет изменять данные в базе. Он͕ как и форма͕ имеет методы
Append
,
Edit
,

,
Po
st
,
Cancel
.
Главным отличием от формы является то͕ что метод
Post

сохраняет данные не
в базе͕ а в наборе данных (подобно подчиненным формам). Для отправки изменений в базу
используется метод
ApplyUpdates
.
Метод
CancelUpdates

может отменить все изменения
,

п
роделанные
в наборе до вызова
ApplyUpdates
.

42


Необходимым условием для возможности изменений данных в базе является указание в
SQL
-
запросе
за словом «
from
» имени формы

и наличие поля «
id
»

формы
. Класс автоматически генерирует
инструкции
Insert
,
Update

и
Dele
te
.
Набор полей формы͕ передаваемых в инструкции
Insert

и
Update
,
берется из
SQL
-
выражения.

Пример:

select

pt
.
id
,
pt
.[товар]
,
pt
.[цена]
,
t
.[
название
]

from

[приход товара]
pt

inner

join

[
товары
]
t

on

pt
.[
товар
]=
t
.
id

Красным выделено
,

данные какой формы буд
ут изменят
ь
ся и
поля
,
которые будут изменены
.

Кроме того класс автоматически определяет генератор͕ который связан с формой. Так что при
добавлении записи͕
id

будет автоматически заполнен. Обращение к генератору тоже занимает какое
-
то время͕ поэтому для уск
орения массового добавления записей вы можете устанавливать
id

вручную͕
без помощи генератора. Для этого установите свойство
UseGenerator

в
False
.

Правда͕ вам все равно
придется корректировать генератор для обеспечения нормальной работы формы. ото делается

процедурой
SQLExecute
.

Выполнение произвольных
SQL
-
инструкций

Процедура
SQLExecute

позволяет выполнить произвольный
SQL
-
скрипт
,
передаваемый в параметр
SQL
.

procedure

SQLExecute(
const

SQL: String)

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


Понять какая таблица связана с формой можно по ее идентификатору (свойство
Id
).
К идентификатору
добавляется префикс «
t
»
:

„t‟ +
IntToStr(Form.Id)

Поле таблицы можно определить по идентификатору

dx
-
компонента
:

„f‟ + IntToStr(dxEdit.Id)

РедТктор 31,
-
вырТжений

Редактор поможет вам составить выражение Sv[. Откройте редактор:

Рис. 18


43



Рис. 19

Прямо в редакторе можно проверить выраж
ение. Результат работы запроса отображается внизу.
Нажмите вторую кнопку на панели инструментов͕ чтобы скопировать выражение в буфер обмена.
Теперь вы можете его вставить в скрипт. Строки обрамляются в кавычки и соединяются символом

«+». Можно сделать наоб
орот͕ вставить скопированный текст Sv[ из скрипта в редактор. Для этого
нажмите третью кнопку на панели инструментов. Лишние кавычки и символы «+» удаляются.

Сводные тТблицы, тТблицы и 31,
-
зТпросы

Сводные таблицы обычно используются в связке с запросом (Td
xvueryDrid). Но если запрос не
привязывать͕ то их можно использовать для отображения произвольных данных͕ например
полученных Sv[
-
запросом.

Также можно использовать таблицу

(подчиненную форму)

для отображения результата Sv[
-
запроса.
оти данные уже можно ис
пользовать для печати шаблона.



44


РТзрТботкТ рТсширений

В
DataExpress

расширения бывают двух видов: функции и действия.
Они р
азрабатываются средствами
DataExpress

и представляют собой скрипты на
Pascal

Script
.

В редакторе скриптов создается модуль
расширени
й
͕ пишется скрипт͕ затем используется в текущей базе или экспортируется для
использования в других базах. В одном модуле могут быть расширения обоих видов. Расширения
позволяют непрограммистам использовать дополнительный функционал.

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

В специ
альном комментарии
{@
module

.. @}
пишется автор͕ версия и описание модуля расширений.

{@module
Author=
Автор

Version=1.0

Description=
Назначение

модуля

@}

͙

Всего 3 поля:



Author


информация об

авторе.



Version


версия

модуля.



Description


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

строк.

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


Функции

отот вид расширений позволяет дополнить выражения новыми функциями.

В специальном
комментарии
,@function ͙ @-
пишется спецификация функции.

{@function
Name=FormName

45


Args=
Result=s

Group
=Мои функции

Description=Эта функц
ия возвращает имя текущей формы
@}


function

begin

Result := Self.FormCaption;

end
;


{@function
OrigName=ToWordsBel
Name=ToWordsBel
Args=n

Result=s

Group=Функции преобразования

Description=Эта функция возвращает число прописью на белор
усском языке.
@}


function

ToWordsBel(N: Double): String;
begin



e
nd
;

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



OrigName


исходное имя функции в

модуле.



Name


имя функции͕ используемое в

выражениях.



Args


типы аргументов: n


число͕ s


строка͕ d



дата͕ t


время͕ b


логический͕ v


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

д.



Result


тип результата. Используются те же символы͕ что и в

Args.



Group


название группы͕ в которой будет находит
ь
ся функция в окне

«дункции».



Description


описание функции. Отображается в окне «дункции». Описание может быть
записано в несколько строк. Можно использовать некоторые

html
-
теги.

Нужно строго соблюдать состав и последовательность полей. В случае нарушения правил͕ компилято
р
выдаст ошибку.
Комментарии могут находиться в любом месте модуля͕ но рекомендуется писать их
перед функцией.

Возможной проблемой является дублирование имен функций разными разработчиками модулей.
Поэтому старайтесь давать функциям уникальные имена͕ напри
мер͕ добавляя какой
-
нибудь префикс:
EX_EXE/͕ aY_CUb/͕ 5!_CLwaDET и т. д.

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

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

46


Действия

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

{@action

Id=D569B5E1
-
7575
-
445F
-
8DFB
-
54B5FF99595B

OrigName=MyActionProc

Name=Некое действие

Group=Моя группа

UI=

&#xui00;ui

fo
rm 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="
Флажок
" de
�faultvalue="1" /

&#x/gri;퀀/grid

expr name="expr" caption="
Выражение
�" /

&#x/ui0;/ui

Description=
Описание

действия

@}

procedure

MyActionProc(FormName, FieldName: Variant; Grid: TVariantArray2d; Expr:
Variant);

begin

end
;

Параметры:



Id
-

уникальный идентификатор дейст
вия. Программа ищет действие по его идентификатору.
ото любая последовательность символов͕ но лучше использовать для этого DUL5. В редакторе
скриптов DUL5 можно вставить комбинацией /trl
-
Shift
-
G.



OrigName
-

имя процедуры или функции в модуле.



Name
-

назван
ие действия для пользователя.



Group
-

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



UI
-

описание интерфейса в формате Xa[. Компоненты используются для настройки действия.



Description
-

описание действия.

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

Каждый тег соответствует определенному компоненту:



text
-

поле для ввода текста͖



number
-

поле для ввода числа͖



checkbox
-

флажок͖



file
-

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



folder
-

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



expr
-

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



filter
-

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

47




list
-

список значений͖



form
-

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



childform
-

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



query
-

список запросов͖



object
-

список объектов͖



field
-

список полей͖



component
-

список ко
мпонентов͖



report
-

список отчетов͖



template
-

список шаблонов͖



divider
-

разделитель.



grid
-

таблица.

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



name
-

имя компонента͖



caption
-

поясняющая надпись͖



height
-

высота таблицы͖



width
-

ширина столбца таблицы͖



required
-

обязательно
е͖



defaultvalue
-

значение по умолчанию͖



items
-

элементы списка͖



source
-

компонент
-
источник͖



filter
-

фильтр списка.

Каждый компонент должен иметь обязательный атрибут name
-

имя компонента (для разделителя
необязательно). Имя должно содержать только сим
волы латинского алфавита͕ цифры и символ
подчеркивания. Имя не может начинаться с цифры͕ должно быть уникальным в пределах интерфейса.

олементы списка items отделяются друг от друга точкой с запятой: один͖два͖три.

Такие компоненты͕ как expr͕ childform͕ que
ry͕ object͕ field͕ component͕ могут зависеть от другого
компонента. Имя этого компонента указывается в атрибуте source.

Атрибут filter используется в тегах: file͕ field и components.

Атрибуты в тегах

Рассмотрим некоторые атрибуты применительно к тегам. Пер
вые на очереди тег file и атрибут filter. В
данном случае filter определяет фильтр диалогового окна выбора файла. Синтаксис его точно такой же͕
как в компонентах Thpen5ialog и TSave5ialog. Пример:

file name="file" caption="
Запустить

программу
" filter="
При
ложения
�|*.exe" /

Атрибут
source

в теге
expr

определяет форму (
form
)͕ в контексте которой вычисляется выражение.
Если
атрибут не задан͕ то используется текущая форма. Пример:



ource="
my
�form" /

Source в теге filter определяет форму (form)͕ данные которой нужно отфильтровать. Если атрибут не
задан͕ то используется текущая форма.


48


Атрибут source в теге form может определять запрос (query)͕ формы которого показать в списке. Если
а
трибут не указан͕ то список содержит все основные формы.

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

указан͕ то используется текущая форма.

Source в теге query может определять форму (form)͕ подчиненную форму (childform) или объект
(object). Атрибут определяет запросы какой формы будут в списке. Если источник не указан͕ то
используется текущая форма.

Sou
rce в теге object может определять форму или подчиненную форму. Если атрибут не задан͕ то
используется текущая форма.

Source в теге field может определять форму͕ подчиненную форму͕ объект или запрос. Если источник не
указан͕ то используется текущая форма.
Атрибут filter определяет поля какого типа показать в списке.
Типы отделяются точкой с запятой. Возможные значения: text
-

текстовые поля (текст͕ список͕ заметка)͕
number
-

число͕ date
-

дата͕ time
-

время͕ object
-

объект͕ counter
-

счетчик͕ checkbox
-

фл
ажок͕ file
-

файл͕ image
-

изображение. Пример:





Source

в теге
components

может определять форму или подчиненную форму. Если источник н
е задан͕
то используется текущая форма. Атрибут
filter

определяет компоненты какого типа показать в списке.
Типы перечисляются через точку с запятой. В качестве типа используется имя класса.
Пример:



component name="m
ycmp" caption="Компонент" source="myform"
�filter="TdxEdit;TdxComboBox;TdxLabel;TdxButton" /

Зависимость может иметь несколько уровней.
Пример:





obje
ct name="obj" caption="Объект" source="mychildform" />





Если в родительском компоненте меняется значение͕ то подчиненные компоненты

очищаются. ото
относится только к спискам.

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

Атрибут required можно включить в любой тег (правда͕ для grid он не имеется смысла). При
сохранении
программа выдаст сообщение͕ если какой
-
то из обязательных параметров не заполнен.

Атрибут defaultvalue определяет значение по умолчанию для компонента. Для флажка возможно
единственное значение: 1. Остальные значения будут проигнорированы.

Атриб
ут caption определяет поясняющую надпись. Для разделителя также можно указать надпись.

Таблицы

Вы можете задавать не просто отдельные компоненты͕ а целые массивы компонентов. Для этого
используются таблицы. Синтаксис очень простой. итобы определить столбцы

и типы компонентов͕
достаточно вышеперечисленные теги перечислить между тегами ... Пример:

49


form name="myform" caption="
Форма
�" /

grid name="fields" caption="
Поля
�" height="150"

field name="field" caption="
Поле
" source="
my
form" filter="text
�" /

checkbox name="mychk" caption="
Флажок
�" width="80" /

&#x/gri;퀀/grid

Таблице можно задать высоту с помощью атрибута height. Текст заголовков берется из атрибута
caption вложенных тегов. Если ширина width не задана͕ то ширина колонки определяется
автоматичес
ки. йирину колонок менять нельзя. Если в таблице определен только один компонент͕ то
заголок таблицы скрывается. Если в таблице определены зависимые компоненты͕ то при изменении
значения в родительском компоненте ячейки
НЕ стираются
.

Символы внутри атрибут
ов <͕ > и " должны быть заменены на <͖ &gr͖ "͖ соответственно.

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

иисло параметров в процедуре должно совпадать с количеством компонентов͕ не включая
компоненты в тегах grid и разделители divider. Каждый

параметр должен иметь тип Variant. Параметр
для тега grid должен иметь тип TVariant!rray2d͕ который представляет собой двухмерный массив: array
of array of Variant. Первое измерения
-

это строки͕ второе
-

столбцы. Параметры и элементы массива
могут быть д
вух типов: 5ouble (компоненты number͕ checkbox) и String (остальные). Параметр может
быть равен bU[[͕ если компонент был добавлен позже͕ чем были сохранены параметры.

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

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

ПодключТемые действия

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


подключаться к
событиям формы и других ко
мпонентов

и выполняться при наступлении этих событий.
Действие
подключается

в свойс
тве формы «Подключить действие». Подключаемые действия нельзя
использовать в кнопке (в свойстве «Действие»
)͕ и наоборот͕ клик
-
действия нельзя подключать.

итобы
отличить одни

действия от других разработчик должен
указать в описании
͕ где его можно применять.


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

Кроме того
бывает необходимость

сохранять старые обработчики событий и вызывать их в новых͕ чтобы не нарушить работу скрипта и
других расширений.

Пример подключаемого действи
я:

{@action

Id=BE798939
-
0563
-
4DC7
-
8789
-
BBB636BD45FA

OrigName=VisibleByCondition

Name=Видимость компонентов по условию

Group=DEMO

50


&#xui00;UI=ui


expr name="condition" caption="
Условие
�" required="1"/


grid name="grid" caption="
Компоненты
�"


component name
�="cmp" required="1"/


&#x/gri;퀀/grid

&#x/ui0;/ui

Description=Обеспечивает видимость компонентов по условию. Компонент видимый,

если условие истинно. Пример условия:



[дата]<>null



Это подключаемое действие.

@}


type


TVCRec =
record


Fm
: TdxForm;


Expr: String;


Cmps: TVariantArray2d;


AfterScroll, AfterCancel: TNotifyEvent;


FieldChange: TFieldChangeEvent;


end
;


var


VCData:
array of

TVCRec;


VC_OldDBClose: TNotifyEvent;


// Обработчик события закрытия базы данных

proced
ure VC_DBClose(Sender: TObject);

begin




if

�VC_OldDBClose
nil then

VC_OldDBClose(Sender);

end
;


// Поиск нужного элемента массива по форме

function


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

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


// Находим наш элемент




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


if

�VC.AfterScroll
nil then

VC.AfterScroll(Sender);


// Само действие



end
;


51


// Действие при отмене изменений записи

procedure

VC_AfterCancel(Sender: TObject);

var


VC: TVCRec;

begin




if
VC.
�AfterCancel
nil then

VC.AfterCancel(Sender);



end
;


// Действие при изменении поля

procedure

VC_FieldChange(Sender, Control: TObject;
const

FieldName: String);

var


VC: TVCRec;

begin




if

VC.Fiel
�dChange
nil then

VC.FieldChange(Sender, Control, FieldName);



end
;


// Эту функцию вызывает программа, когда выполняет подключаемое действие.

function

VisibleByCondition(aExpr: String; aCmps: TVariantArray2d): Boolean;

var


i: Integ
er;

begin


Result := True;



i := Length(VCData);


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


// чтобы можно было выполнить какие
-
либо завершающие действия, например,


//
освободить

память
.


if

i = 0
then


begin



VC_OldDBClose := MainWindow.OnDatabaseClose;


MainWindow.OnDatabaseClose := @VC_DBClose;


end
;


// Каждый вызов действия увеличивает массив на один элемент.




// Сохраняем в последний элемент все необходимое для дальнейшей
работы действия,


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


with

VCData[i]
do


begin


Fm := Self;


Expr := aExpr;


Cmps := aCmps;


AfterScroll := Self.OnAfterScroll;


AfterCancel := Self.OnAfterCancel;


FieldChange := Self.OnFieldChange;


Self.O
nAfterScroll := @VC_AfterScroll;


Self.OnAfterCancel := @VC_AfterCancel;


Self.OnFieldChange := @VC_FieldChange;


end
;

end
;

Несмотря на относительную сложность
,

разработк
а

подключаемого действия

ведется по шаблону:

1.

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

2.

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

3.

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

4.

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

5.

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

6.

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

7.

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

8.

В обработчиках первым делом ищем нужный элемент массива. Если

Sender

обработчика не
52


форма͕ а другой компонент͕ то

добраться до формы можно через свойство
Owner

компонента
или другим способом. В принципе͕ поиск элемента массива можно делать не по форме͕ а по
другому компоненту.

9.

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

10.

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

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




Приложенные файлы

  • pdf 7766988
    Размер файла: 2 MB Загрузок: 0

Добавить комментарий