Проверка типа и значения поля
При выполнении программы можно выяснить тип данных конкретного поля. Это удобно делать в случае, когда, например, типы данных полей таблиц БД заранее неизвестны.
Тип данных поля таблицы определяет свойство DataType типа TFieldType, принимающее следующие значения:
□ f tUnknown (тип неизвестен или неопределен);
□ ftstring (короткая строка длиной не более 255 символов);
□ ftSmallint (короткое целое число);
□ ftlnteger (целое число);
□ ftword (целое число без знака);
□ ftBoolean (логическое значение);
□ ftFloat (вещественное число);
□ ftCurrency (денежное значение);
120
Часть I. Основы работы с базами данных
П ftBCD (число в формате BCD (двоично-десятичный формат));
□ ftDate (дата);
□ ftTime (время);
□ f tDateTime (дата и время);
□ ftBytes (байтовое значение фиксированной длины);
□ f tVarBytes (байтовое значение переменной длины);
□ ftAutoinc (автоинкрементное значение);
□ ftBlob (BLOB-объект);
□ ftMemo (текст Memo);
□ ftGraphic (графический объект);
□ ftFmtMemo (форматированный текст Memo);
□ ftParadoxOle (поле OLE для таблицы Paradox);
□ ftDBaseOle (поле OLE для таблицы dBase);
□ f tTypedBinary (типированное двоичное значение);
□ ftCursor (курсор для хранимой процедуры Oracle);
□ ftFixedChar (фиксированное количество символов);
□ ftwideString (строка);
□ ftLargeint (длинное целое число);
□ ftADT (значение абстрактного типа);
□ ftArray (массив);
□ ftReference (REF-поле);
□ ftDataSet (DataSet-поле).
Программист с помощью специальных свойств может задать ограничения для вводимых в поля значений, а также проверить введенные значения.
Набор символов, допускаемых при вводе значений поля, зависит от типа данных поля:
□ ftBoolean — все символы;
□ ftsmallint — цифры 0.. 9, знаки + и -;
□ ftword — цифры 0.. 9, знаки + и -;
|
□ ftAutoinc — цифры 0.. 9, знаки + и -;
□ ftDate — все символы;
□ ftlnteger — цифры 0.. 9, знаки + и -;
□ ftTime — все символы;
□ ftCurrency — цифры 0.. 9, знаки + и -, символы Е или е, разделитель разрядов целой и дробной части;
Глава 5. Компоненты доступа к данным
121
П ftDateTime — все символы;
□ ftFloat — цифры 0.. 9, знаки + и -, символы Е или е, разделитель разрядов целой и дробной части;
□ ftBCD — цифры 0.. 9, знаки + и -, символы Е или е, разделитель разрядов целой и дробной части;
□ ftString, ftVarBytes, ftBytes, ftBlob, ftDBaseOle, ftFmtMemo, ftGraphic, ftMemo, ftParadoxOle, ftTypedBinary, ftUnknown и ftCursor — все символы.
Отметим, что разделитель разрядов целой и дробной части числа (десятичный разделитель) зависит от установок Windows, выполненных через Панель управления.
Набор допустимых для поля символов содержит свойство ValidChars типа TFieldChars, который описан как множество символов:
type TFieldChars = set of Char;
Чтобы проверить, разрешен ли символ для ввода в качестве значения поля, удобно использовать метод IsValidChar (InputChar: Char): Boolean. Он возвращает значение True, если заданный параметром input Char символ является для данного поля допустимым, и False — если символ не допускается.
Вот как осуществляется проверка допустимости символа в программе:
if not Tablel.Fields[2].IsValidChar(Editl.Text[1]) then MessageDlg('Символ "' + Editl.Text[1] + '" не допустим!', mtError, [mbOK], 0);
Если первый символ текста, введенного в компонент Editl, не является допустимым для поля (третьего в списке полей) набора данных Tablel, то выдается сообщение об ошибке.
(Замечание^
Проверка на корректность символа не гарантирует отсутствие ошибок при вводе значений полей. Например, для числового поля типа TlntegerField не подойдет значение 12++3, хотя каждый символ является допустимым.
|
Для полей числовых типов, например, объектов типа TlntegerField и TFloatField свойства MinValue и MaxValue позволяют установить минимальное и максимальное возможные значения, которые могут быть введены в соответствующее поле. Тип этих свойств определяется конкретным объектом типа TField.
Так устанавливается ограничение вводимых значений в программе:
TablelPrice.MinValue:= 0;
TablelPrice.MaxValue:= 9999.99;
TablelNurrOoer.MinValue:= 0;
TablelNurrOoer.MaxValue:= 1000;
122
Часть I. Основы работы с базами данных
Здесь для поля цены (вещественный тип) устанавливается допустимый диапазон о.. 99 99.9 9, а для поля количества (целый тип) — диапазон о.. юоо.
Ограничения на вводимые значения можно определить также с помощью свойства CustomConstraint типа string. В этом свойстве допустимый диапазон задается с помощью конструкций, похожих на команды SQL или фильтры для отбора данных. Отличие заключается в том, что команды SQL и фильтры действуют при формировании наборов данных, а конструкция свойства CustomConstraint — при задании ограничений на вводимые значения. Например:
TablelPrice.CustomConstraint:= 'Price >= 0 and Price <= 9999.99'; TablelNumber.CustomConstraint:= 'Number >= 0 and Number <= 1000';
Здесь для полей цены и количества устанавливаются те же диапазоны допустимых значений, что и в предыдущем примере.
Если для поля некоторым способом задан диапазон допустимых значений, то при любой попытке установить поле в значение, выходящее за границы этого диапазона, вызывается исключение. При этом пользователю выдается соответствующее сообщение, а значение отвергается. Контроль значений относится не только к вводу со стороны пользователя, он также действует и при изменении значения поля программным способом.
|
С ПОМОЩЬЮ свойства ConstraintErrorMessage типа String разработчик при желании может определить собственное сообщение, которое будет выдаваться при нарушении границ диапазона, например:
TablelNumber.CustomConstraint:= 'Number >= 0 and Number <= 10'; TablelNumber.ConstraintErrorMessage:=
'Количество должно находиться в диапазоне 0.. 10';
Разработчик может не только ограничивать значения, вводимые в поля, но и задавать через свойство DefaultExpression типа string значение по умолчанию, которое автоматически заносится в поле при добавлении новой записи. Отметим, что это свойство строкового типа, поэтому его значения заключаются в кавычки.
Пример установки значения по умолчанию:
TablelNumber.DefaultExpression:= '100';
Чтобы проверить, действуют ли для поля ограничения, заданные в свойствах CustomConstraint, DefaultExpression, а также В ImportedConstraint (ограничения, налагаемые сервером), используется свойство HasConstraints типа Boolean. Это свойство, действующее во время выполнения приложения, принимает значение True, если установлено хотя бы одно из перечисленных ограничений.
Кроме проверки выхода за границы допустимых значений, программист может выполнить и более сложную проверку, используя обработчики событий OnSetText (типа TFieldSetTextEvent, OnValidate) и OnChange (типа TFieldNotifyEvent),
Глава 5. Компоненты доступа к данным
123
возникающих в указанном здесь порядке при изменении значения поля. Типы этих событий описаны так:
type TFieldSetTextEvent = procedure (Sender: TField; const Text: string) of object;
type TFieldNotifyEvent = procedure (Sender: TField) of object;
Все упомянутые события возникают до изменения значения поля, поэтому программист может в необходимых случаях отказаться от внесения изменения. Отказ от изменения значения поля для этих событий выполняется различными способами. При использовании событий OnValidate и OnChange программист возбуждает исключение, в результате чего запись значения в поле не происходит. Если исключение не генерируется, то новое значение заносится в поле. Так как обработчик не получает нового значения поля, для доступа к нему нужно использовать свойства Value или Asxxx. Следует иметь в виду, что эти свойства возвращают новое (предлагаемое для утверждения) значение поля, которое может быть и не принято, в этом случае происходит возврат к старому значению.
При редактировании поля пользователем события OnValidate и OnChange не вызываются до тех пор, пока не будет выполнена попытка сохранить изменения, например, нажатием клавиши <Enter>.
Рассмотрим на примере, как осуществляется проверка вводимых значений.
В поле code запрещается ввод значений 1 и 3, которые зарезервированы для специальных целей. При попытке ввода неправильных значений после соответствующей проверки генерируется "тихое" исключение (посредством вызова процедуры Abort). В результате попытка ввода отвергается, при этом никакие сообщения пользователю не выдаются.
procedure TForial.TablelNumberValidate(Sender: TField); begin
if (Tablel.FieldByName('Code').AsString = 4') or (Tablel.FieldByName('Code').AsString = '3') then Abort; end;
Для выдачи сообщения о возникшем исключении в дополнение к процедуре Abort можно использовать, например, функцию MessageDlg, выводящую диалоговое окно. Кроме того, вместо вызова с помощью Abort "тихого" исключения можно вызвать обычное исключение, например, следующим образом:
Raise Exception.Create('Код не может равняться значениям 1 и 3!');
Для события OnSetText действует противоположный порядок принятия изменений и отказа от них. Параметр Text обработчика этого события содержит новое значение, которое предложено для занесения в поле, однако запись этого значения не осуществляется автоматически. Поэтому программист должен "вручную" занести предложенное значение в поле: если этого не сделать, то поле остается без изменений. Таким образом, по умолчанию в обработчике события OnSetText новое значение отвергается.
124
Часть I. Основы работы с базами данных
Вот еще один пример проверки вводимых значений:
procedure TForial.TablelNumberSetText(Sender: TField; const Text: String);
begin
if not ((Text = 4') or (Text = '3'))
then Tablel.FieldByName('Code').AsString:= Text; end;
Ряд полей, например, индексное поле, не могут быть пустыми, в этом случае у поля свойство Required типа Boolean имеет значение True. Для проверки полей, содержат ли они отличное от пустого значение, используется свойство isNull типа Boolean. Это свойство возвращает значение True, если значение поля не задано, и значение False — в противном случае. Свойство isNull можно использовать, например, в обработчиках событий OnSetText, OnValidate и OnChange:
procedure TFo rial.TablelCodeValidate(Sender: TField);
begin
if (TablelCode.Required) and (TablelCode.isNull)
then Raise Exception.Create('Поле кода не может быть пустым!'); end;
Иногда перед занесением значения в некоторое поле необходимо проверить, является ли символ допустимым. Для этого можно использовать метод isValidChar, проверяющий допустимость заданного символа, и свойство ValidChars, возвращающее набор допустимых для данного поля символов.
(Замечание^
Некоторые из описанных ограничений на значения полей также могут быть заданы при создании таблицы БД (запрет пустого значения и задание диапазона допустимых значений). d этом случае ограничения действуют на физическом уровне и не могут быть отменены.
Форматирование отображаемого значения поля
То, как выглядит значение поля в визуальных компонентах, зависит от типа поля, а также от системных установок Windows и BDE. Часто возникает необходимость изменить этот вид при отображении значений или их редактировании. Для этого используется форматирование выводимой информации.
(Замечание^
Названное форматирование относится только к отображению значений в визуальных компонентах и не затрагивает вид и размещение данных в таблице БД.
Свойство DisplayFormat типа string управляет отображением значений полей в визуальных компонентах, например, DBGrid и DBEdit. Это свойство дей-
Глава 5. Компоненты доступа к данным
125
ствует для числовых полей, а также для полей даты и времени. В качестве значения свойства DisplayFormat задается маска, определяющая формат отображения поля.
Эта маска состоит из трех секций, разделенных символом;. Секции задают форму отображения положительных, отрицательных и нулевых значений соответственно. Если задана только одна секция, то она применяется для вывода всех значений. В маске можно использовать следующие управляющие символы:
□ 0 — цифра числа, незначащие нули отображаются;
□ # — цифра числа, незначащие нули гасятся;
□. — разделитель целой и дробной части числа;
□, — разделитель тысяч;
□ Е+ или е+ — разделитель мантиссы и порядка для чисел в форме с плавающей точкой, отображаются положительный и отрицательный знаки порядка;
□ е- или е------- разделитель мантиссы и порядка для чисел в форме с плавающей точкой, отображается только отрицательный знак порядка;
□ "хх" и 'хх' — символы, выводимые без изменений; символы, заключенные в кавычки (двойные или апострофы), включаются в отображаемое значение;
□; — разделитель секций маски для положительных, отрицательных и нулевых значений.
Приведем примеры масок:
□ 000Е-00 или 000Е+00 — для чисел в форме с плавающей точкой;
□ #####0.00 или 000000.00 — для чисел в форме с фиксированной точкой;
□ #####0.00' рублей' — для денежных сумм;
□ ####0;-####0;0— отдельно для положительных, отрицательных и нулевых значений.
Свойство EditFormat типа string задает маску, используемую при форматировании значения числового поля перед его отображением для редактирования в визуальном компоненте. Формирование этой маски не отличается от формирования маски, задаваемой в свойстве DisplayFormat.
Свойство EditMask типа string задает маску, используемую при редактировании значения в визуальном компоненте. Маска позволяет ограничить число вводимых пользователем символов и тип вводимых символов (алфавитный, цифровой и т. д.). Кроме того, во вводимую информацию можно вставить дополнительные символы (разделители при вводе даты, времени и т. п.). С помощью свойства EditMask удобно вводить телефонные номера, даты, почтовые индексы и другую информацию подобного рода, имеющую заранее определенный формат.
Способы задания маски, содержащейся в свойстве EditMask, рассмотрены в главе 6, посвященной визуальным компонентам.
126
Часть I. Основы работы с базами данных
Приведенные свойства DisplayFormat и EditMask независимо друг от друга управляют форматированием значения поля при отображении и при редактировании. Кроме них, для объекта типа TField есть событие OnGetText типа TFieldGetTextEvent, в обработчике которого на программном уровне можно одновременно управлять форматом данных и при отображении, и при редактировании. Это событие генерируется при каждом обращении к свойствам DisplayText и Text. Тип события OnGetText описан так:
type TFieldGetTextEvent = procedure (Sender: TField; var Text: string; DisplayText: Boolean) of object;
Параметр Text содержит значение, которое выводится в визуальном компоненте. Программист должен задать это значение. Логический параметр DisplayText указывает, для каких целей выводится значение: для отображения
(DisplayText = True) или для редактирования (DisplayText = False).
Рассмотрим пример, в котором используется форматирование отображаемых и редактируемых значений:
procedure TForml.TableINameGetText(Sender: TField; var Text: String;
DisplayText: Boolean);
begin
if DisplayText then Text:= TablelName.AsString
else Text:= AnsiUpperCase(TablelName.AsString); end;
procedure TForml.TablelPercentGetText(Sender: TField; var Text: String;
DisplayText: Boolean);
begin
if DisplayText then Text:= TablelPercent.AsString + '%'
else Text:= TablelPercent.AsString; end;
Значение поля Percent отображается в визуальных компонентах с знаком %. При редактировании этого поля знак процента отсутствует. При редактировании значения поля Name оно выводится строчными буквами. Отметим, что если для перевода символов строки в верхний регистр вместо функции AnsiUpperCase использовать uppercase, то символы русского алфавита будут преобразовываться некорректно.
(_____ ЗамечаниеJ
Если определен обработчик события OnGetText, то свойства DisplayFormat и EditMask не действуют.
Свойство DisplayWidth типа integer определяет число символов, предназначенных для вывода значения поля в визуальном компоненте (обычно в сетке DBGrid), который связан с этим полем. По умолчанию значение этого свойства определяется шириной физического поля таблицы, заданной при его создании.
Глава 5. Компоненты доступа к данным
127
(_____ ЗамечаниеJ
Ширина столбца компонента-сетки DBGrid также зависит от значения свойства Width этого столбца, задающего ширину в пикселах.
Программист может изменить не только значение, но и заголовок поля, используемый как название столбца, например, в компоненте DBGrid. Заголовок поля определяется свойством DisplayLabel типа string. По умолчанию значением этого свойства является имя поля (свойство FieldName), однако, в отличие от последнего, свойство DisplayLabel доступно и для записи, и его можно использовать, например, для настройки пользователем интерфейса приложения.
Пример настройки заголовка поля:
procedure TForml.ButtonlClick(Sender: TObject);
begin
TablelName.DisplayLabel:= Editl.Text;
end;
Здесь при нажатии кнопки заголовку поля Name присваивается текст, введенный в компонент Editl. Если это поле отображается в компоненте DBGrid, то соответствующий столбец сетки также изменяет свое значение на указанное.
Источник данных
Источник данных используется как промежуточное звено между набором данных и визуальными компонентами, с помощью которых пользователь управляет этим набором данных. В Delphi источник данных представлен компонентом
DataSource.
Для указания набора данных, с которым связан источник данных, служит свойство DataSet типа TDataSet последнего. Визуальные компоненты связаны с источником данных через свои свойства DataSource. Обычно связь между источником и набором данных устанавливается на этапе проектирования в Инспекторе объектов, однако при необходимости эту связь можно установить или разорвать динамически. При смене у компонента DataSource набора данных визуальные компоненты автоматически подключаются к новому набору данных.
Указать набор данных можно, например, так:
DataSource2.DataSet:= Nil; DataSourcel.DataSet:= Table2;
Здесь для компонента DataSource2 связь с набором данных разрывается, а для компонента DataSourcel назначается набор данных ТаЫе2.
Для анализа состояния, в котором находится набор данных, можно использовать свойство State типа TDataSetState. При каждом изменении состояния набора данных для связанного с ним источника данных DataSource генерируется событие OnStateChange типа TNotifyEvent.
128
Часть I. Основы работы с базами данных
Если набор данных является редактируемым, то свойство AutoEdit типа Boolean определяет, может ли он автоматически переводиться в режим модификации при выполнении пользователем определенных действий. Например, для компонентов DBGrid и DBEdit таким действием является нажатие алфавитно-цифровой клавиши, когда компонент находится в фокусе ввода. По умолчанию свойство AutoEdit имеет значение True, и автоматический переход в режим модификации разрешен. Если необходимо защитить данные от случайного изменения, то одной из предпринимаемых мер является установка свойства AutoEdit в значение False.
(_____ ЗамечаниеJ
Значение свойства AutoEdit влияет на возможность редактирования набора данных только со стороны пользователя. Программно можно изменять записи независимо от значения этого свойства.
Без учета значения свойства AutoEdit пользователь может переводить набор данных в режим модификации путем нажатия кнопок компонента DBNavigator.
При изменении данных текущей записи генерируется событие OnDataChange типа TDataChangeEvent, описанного так:
type TDataChangeEvent = procedure (Sender: TObject; Field: TField) of object;
Параметр Field указывает на измененное поле; если данные изменены более чем в одном поле, то этот параметр имеет значение Nil. Следует иметь в виду, что в большинстве случаев событие OnDataChange генерируется и при переходе к другой записи. Это происходит, если хотя бы одно поле записи, ставшей текущей, содержит значение, отличное от значения этого же поля для записи, которая была текущей. Событие OnDataChange можно использовать, например, для контроля положения указателя текущей записи и выполнения действий, связанных с его перемещением. Это событие генерируется также при открытии набора данных.
Вот как осуществляется контроль перемещения указателя текущей записи:
procedure TForial.DataSourcelDataChange(Sender: TObject; Field: TField);
begin
Labell.Caption:= 'Запись номер ' + IntToStr(Tablel.RecNo);
end;
При модификации текущей записи, кроме события OnDataChange, генерируется еще событие OnUpdateData типа TNotifyEvent. Оно возникает непосредственно перед записью данных в БД, поэтому в его обработчике можно предусмотреть дополнительный контроль и обработку введенных в поля значений, а также некоторые другие действия, например, отказ от изменения записи.
Иногда в визуальных компонентах требуется отключать отображение полей записей набора данных, например, при переборе записей в цикле их обработки,
Глава 5. Компоненты доступа к данным
129
поскольку при этом возникает мелькание данных вследствие их быстрой смены. Для управления отображением записей можно использовать свойство Enabled типа Boolean источника данных.
Рассмотрим пример, демонстрирующий, как производится такое управление:
procedure TForml.ButtonlClick(Sender: TObject); Var n: integer; begin
// Отключение отображения записей в визуальных компонентах DataSourcel.Enabled:= False; Tablel.First;
for n:= 1 to Tablel.RecordCount do begin // Обработка записи набора данных Tablel
Tablel.Next;
end; // Включение отображения записей в визуальных компонентах DataSourcel.Enabled:= True; end;
В цикле перебираются все записи набора данных Tablel. Перед началом цикла отображение записей в визуальных компонентах отключается, а после цикла — включается. Эти действия также можно выполнить, используя методы
DisableControls и EnableControls набора данных.
ЧАСТЬII
ТЕХНОЛОГИИ ДОСТУПА К ДАННЫМ
Глава 6
Визуальные компоненты для работы с данными
Визуальные компоненты для работы с данными расположены на странице Data Controls Палитры компонентов и предназначены для построения интерфейсной части приложения. Они используются для навигации по набору данных, а также для отображения и редактирования записей. Часто эти компоненты называют элементами, чувствительными к данным.
Одни визуальные компоненты для работы с данными предназначены для выполнения операций с полями отдельной записи, они отображают и позволяют редактировать значение поля текущей записи. К таким компонентам относятся, например, однострочный редактор DBEdit и графическое изображение DBimage.
Другие компоненты служат для отображения и редактирования сразу нескольких записей. Примерами таких компонентов являются сетки DBGrid и DBCtrlGrid, выводящие записи набора данных в табличном виде.
Визуальные компоненты для работы с данными похожи на соответствующие компоненты страниц Standard, Additional и Win32 и отличаются, в основном, тем, что ориентированы на работу с БД и имеют дополнительные свойства DataSource и DataField. Первое из них указывает на источник данных — компонент DataSource, второе — на поле набора данных, с которым связан визуальный компонент. Например, однострочный редактор DBEdit работает так же, как однострочный редактор Edit, отображая строковое значение и позволяя пользователю изменять его. Отличие компонентов состоит в том, что в редакторе DBEdit отображается и изменяется значение определенного поля текущей записи набора данных.
Отметим, что для всех визуальных компонентов, предназначенных для отображения и редактирования значений полей, при изменении пользователем их содержимого набор данных автоматически переводится в режим редактирования. Произведенные с помощью этих компонентов изменения также автоматически сохраняются в связанных с ними полях при наступлении определенных событий, таких, например, как потеря фокуса визуальным компонентом или переход к другой записи набора данных.
134
Часть II. Технологии доступа к данным
При программном изменении содержимого этих визуальных компонентов набор данных не переводится в режим редактирования автоматически. Для этой цели в коде должен предварительно вызываться метод Edit набора данных. Чтобы сохранить изменения в поле (полях) текущей записи, программист также должен предусмотреть соответствующие действия, например, вызов метода Post или переход к другой записи набора данных.
В табл. 6.1 приводятся так называемые стандартные, дополнительные и 32-разрядные визуальные компоненты, расположенные на страницах Standard, Additional и Win32 Палитры компонентов, а также соответствующие им визуальные компоненты для работы с данными (страница Data Controls).
Таблица 6.1. Соответствие визуальных компонентов, расположенных на разных страницах Палитры компонентов
Комоненты страниц Standard, Additional и Win32
Компоненты страницы Data Controls
Замечание
J
Часть компонентов(QRLabel, QRRichEdit, QRDBRichEdit, QRImage, QRDBImage, QRShape, QRChart), используемых для формирования отчетов в предыдущих версиях Delphi (изъятая страница QReport Палитры компонентов), тоже имеет свои аналоги среди других визуальных компонентов. Для обеспечения обратной совместимости компоненты страницы QReport размещены в пакете dclqrt70.bpl в папке \Delphi 7\Bin и при необходимости могут быть установлены в Палитру компонентов.
В этой главе мы рассмотрим особенности отдельных визуальных компонентов, предназначенных для работы с данными.
Глава 6. Визуальные компоненты для работы с данными
135
Отображение и редактирование значения логического поля
Логическое поле (поле логического типа) может содержать одно из двух значений: True (истина) или False (ложь). Разрешается использование прописных букв и сокращение вводимого значения, т. е. допустимы значения True, true,
tru, Tr, t И Т. Д.
Для отображения и изменения значения логического поля можно использовать редактор DBEdit. Однако удобнее выполнять эти действия с помощью флажка (независимого переключателя) DBCheckBox, который позволяет "включить" или "выключить" значение логического поля.
Флажок DBCheckBox является аналогом рассмотренного ранее компонента Checkbox, поэтому здесь мы остановимся только на свойствах, характерных именно для этого флажка.
Компонент DBCheckBox выглядит на экране как квадратик (флажок) с текстовым заголовком (см. рис. 6.1). Если в нем находится галочка (при этом говорят, что флажок "включен" или "установлен"), то связанное с этим флажком логическое поле текущей записи содержит значение True. Если же квадратик пуст (флажок снят), то логическое поле текущей записи содержит значение False.