Глава 18
Отображение и управление данными
До этого момента мы рассмотрели аспекты создания приложений баз данных, касающиеся организации доступа к данным и создания в приложениях наборов данных. Теперь более подробно остановимся на вопросах отображения данных в приложениях (интерфейс приложений) и управления этими данными.
Отображение данных обеспечивает достаточно представительный набор компонентов VCL Delphi. Многие из них унаследованы от компонентов, инкапсулирующих стандартные элементы управления. Для связи с набором данных эти компоненты используют компонент TDatasource.
Механизмы управления данными реализованы в компонентах наборов данных и активно взаимодействуют с компонентами отображения данных.
В этой главе рассматривается следующий ряд вопросов.
Редактирование данных
Редактирование данных — самая распространенная операция, которая выполняется в наборе данных приложений баз данных. Для обеспечения этой возможности приложение должно содержать один или несколько компонентов отображения данных.
Перед началом редактирования набор данных необходимо перевести в состояние редактирования (см. ниже). Для этого используется метод Edit. Обычно этот метод используется при необходимости присвоить значение полю программно:
with Tablel do begin
Open;
Edit;
Fields[0].AsString :=" ;
Post;
Close;
end;
В этом фрагменте кода набор данных открывается методом open и переводится в режим редактирования. Затем первое поле обнуляется, для чего используется свойство Fields.
Если редактирование осуществляется через связанные с набором данных компоненты отображения данных, то режим редактирования устанавливается автоматически.
После завершения редактирования необходимо передать все сделанные в текущей записи изменения в базу данных. Для этой операции используется метод post. Этот метод вызывается автоматически при переходе на новую запись. При программном изменении значений метод должен вызываться явным образом.
В приведенном выше фрагменте кода сделанные изменения переносятся в базу данных при помощи метода post, затем набор данных закрывается.
В случае необходимости все изменения, сделанные в текущей записи и не сохраненные в базе данных, можно отменить при помощи метода cancel.
Новую запись в набор данных можно добавить несколькими способами.
Методы Append и AppendRecord используются для добавления записи в конец набора данных. Первый метод создает новую пустую запись. Второй позволяет уже при создании записи ввести в нее значения полей. Для этого используется параметр метода, представляющий собой массив констант:
Tablel.AppendRecord(['Value!', 100, Null, 200, 300.00]);
При необходимости оставить поле незаполненным используется Null для числовых типов данных и ' ' для строк. После применения методов курсор автоматически устанавливается на новую запись. Новая запись автоматически записывается в базу данных.
Если набор данных индексирован, то новая запись располагается в зависимости от значений индексированных полей.
Методы insert и insertRecord позволяют вставить новую запись на месте курсора набора данных. Первый метод создает и вставляет новую пустую запись. Второй позволяет добавлять новую запись вместе со значениями полей. Для этого используется параметр метода, представляющий собой массив констант:
Tablel.InsertRecord(['Value1', 100, Null, 200, 300.00]);
После применения методов курсор автоматически устанавливается на новую запись. Новая запись автоматически записывается в базу данных.
Для удаления текущей записи набора данных используется метод Delete. После удаления курсор устанавливается на следующую запись.
Классификация компонентов отображения данных
Все компоненты отображения данных можно разделить на группы по нескольким критериям (рис. 18.1).
Большинство компонентов предназначены для работы с отдельным полем. То есть при перемещении по записям набора данных такие компоненты показывают текущие значения только одного поля. Для соединения с набором данных через компонент TDataSource предназначено свойство DataaSource.
Поле задастся свойством DataField.
Рис. 18.1. Классификация компонентов отображения данных
Компоненты TDBGrid и TDBCtrlGrid обеспечивают просмотр наборов данных целиком или в произвольном сочетании полей. В них присутствует только свойство DataSource.
Особенную роль среди компонентов отображения данных играет компонент TDBNavigator. Он не показывает данные и не предназначен для их редактирования, зато обеспечивает навигацию по набору данных.
Наиболее часто в практике программирования используются компоненты
TDBGrid,TDBEdit И TDBNavigator.
Для представления и редактирования информации, содержащейся в полях типа Memo, используются специальные компоненты TDBMето и TDBRichEdit.
Для просмотра (без редактирования) изображений предназначен компонент TDBImage.
Отдельную группу .составляют компоненты синхронного'просмотра данных. Они обеспечивают показ значений поля из одной таблицы в соответствии со значениями поля из другой таблицы.
Наконец, данные можно представить в виде графика. Для этого предназначен компонент TDBChat.
Как видите, набор компонентов отображения данных весьма разнообразен и позволяет решать задачи по созданию любых интерфейсов для приложений баз данных.
Ввиду общности решаемых задач, компоненты отображения данных имеют несколько важных общих свойств, которые представлены в табл. 18.1 и в дальнейшем изложении опущены.
Таблица 18.1. Общие свойства компонентов отображения данных
Объявление |
Тип |
Описание |
property DataField: string; |
Pb |
Поле связанного с компонентом набора данных |
property DataSource: TDataSource; |
Pb |
Связываемый с компонентом компонент TDataSource |
property Field: TField; |
Ro |
Обеспечивает доступ к классу TFieid, соответствующему полю набора данных, заданному свойством DataField |
property Readonly: Boolean; |
Pb |
Управляет работой режима "только для чтения" |
Табличное представление данных
Компонент TDBGrid
Этот компонент инкапсулирует двумерную таблицу, в которой строки представляют собой записи, а столбцы — поля набора данных. Далее по тексту этот компонент будет называться термином "сетка" (прямой перевод с английского слова grid), так как термин "таблица" уже занят.
Компонент TDBGrid является потоком классов TDBCUStOmGrid и TCustomGrid. От TCustomGrid наследуются все функции отображения и управления работой двумерной структуры данных. TDBCustomGrid обеспечивает визуализацию и редактирование полей из набора данных, причем TDBGrid только публикует свойства и методы класса TDBCustomGrid, не добавляя собственных.
В сетке можно отображать произвольное подмножество полей используемого набора данных, но число записей ограничить нельзя — в компоненте всегда присутствуют все записи связанного набора данных. Требуемый набор полей можно составить при помощи специального Редактора столбцов, который открывается при двойном щелчке на компоненте, перенесенном на форму или кнопкой свойства columns в Инспекторе объектов. Новая колонка добавляется при помощи кнопки Add New, после этого ее название появляется в списке колонок (рис. 18.2). Для выбранной в списке колонки доступные для редактирования свойства появляются в Инспекторе объектов. Колонки в списке можно редактировать, удалять, менять местами.
При помощи кнопки Add All Fields в сетку можно добавить все поля в набор данных.
Рис. 18.2. Редактор колонок компонента TDBGrid
Каждая колонка компонента TDBGrid описывается специальным классом TColumn, а совокупность колонок доступна через свойство columns компонента, оно имеет тип TDBGridColumns и представляет собой индексированный список объектов колонок. Поле набора данных связывается с конкретной колонкой при помощи свойства FieldMame класса TColumn. При этом в колонку автоматически переносятся все необходимые параметры поля, в частности заголовок поля, настройки шрифтов, ширина поля. После ручного изменения параметров первоначальные значения восстанавливаются методами соответствующих объектов TColumn.
При помощи метода DefauitDrawCoiumnCell и метода-обработчика onDrawCoiumnCell можно управлять процессом отображения данных в ячейках сетки. Метод-обработчик включается только в том случае, если свойство DefaultDrawing имеет значение False.
Метод DefaultDrawDataCeil предназначен только для обеспечения обратной совместимости по коду с более ранними версиями.
Настройка параметров сетки, от которых зависит ее внешний вид и некоторые функции, осуществляется при помощи свойства options (табл. 18.2). Текущая позиция в двумерной структуре данных может быть определена свойствами SelectedField, SelectedRows, Selectedlndex.
При необходимости программист может использовать разнообразные методы-обработчики событий. Среди них есть как стандартные методы, присущие всем элементам управления, так и специфические, имеющиеся только в сетках.
Например, при помощи метода-обработчика OnEditButtonClick можно предусмотреть вызов специализированной формы при щелчке на кнопке в ячейке:
procedure TFomI. DBGridlEditButtonClick (Sender: TObject);
begin
if DBGridI.Selectedlndex = 2 then SomeForm.ShowModal;
end;
Объект колонки TColumn имеет свойство ButtonStyle. Если ему присвоить значение cbsEllipsis, то при активизации ячейки этой колонки в правой части ячейки появляется кнопка.
Таблица 18.2. Свойства и методы компонента TDBGrid
Объявление | Тип | Описание |
Свойства
|
||
property Columns: TDBGridColumns; |
Pb |
Содержит коллекцию объектов TColumn, описывающих колонки сетки |
property DefaultDrawing: Boolean- |
Pb |
Определяет способ визуализации данных в сетке. При значении True данные отображаются автоматически. При значении False используется метод-обработчик OnDrawColumnCell |
property FieldCount: Integer; |
Ro |
Возвращает число видимых колонок сетки |
property Fields[Index: Integer]: TField; |
Ro |
Массив объектов полей набора данных, отображаемых в сетке |
TDBGridOption = (dgEditing,dgAlwaysShowEditor, dgTitles,dglndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect, dgAlwaysShowSelection, dgConfirmDelete, dgCancelOnExit, dgMultiSelect) ; TDBGridOptions = set of TDBGridOption; |
Ro |
Определяет особенности визуализации и по ведения сетки. DgEditing — данные можно редактировать dgAlwaysShowEditor — данные в сетке всегда в режиме редактирования dgTitles — видны заголовки колонок dglndicator — в начале строки виден номер текущей колонки dgColumnResize — колонки можно перемещатьщать и менять их ширину dgColLines — видны линии между колонками dgRowLines — видны линии между строками dgTabs — для перемещения по строкам можно использовать клавиши <Таb> и <Shift>+<Таb> dgRowSelect — можно выделять целые строки, при этом игнорируются установки dgEditing и dgAlwaysShowEditor dgAlwaysShowSelection — выделение текущей ячейки сохраняется, даже если сетка неактивна dgConfirmDelete — при удалении строк появляется запрос о подтверждении операции dgCancelOnExit — созданные пустые строки при уходе из сетки не сохраняются dgMultiSelect — можно выделять несколько строк одновременно |
property Pu SelectedField: TField; |
Ro |
Содержит объект текущего поля сетки |
property Selectedlndex: Integer; |
Ro |
Содержит номер текущей колонки в массиве свойства Columns |
property Ro SelectedRows: TBookmarkList; |
Ro |
Набор закладок на записи набора данных, соответствующих выделенным строкам сетки |
property TitleFont: Т Font; |
Pu |
Шрифт заголовков колонок |
property EditorMode: Boolean; |
Pu |
Показывает, можно ли редактировать текущую ячейку |
property FixedCoior: TColor; |
Pu |
Цвет фона неподвижных ячеек сетки |
Методы |
||
procedure DefaultDrawColumnCell (const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState) ; |
Pu |
Перерисовывает текст в ячейке колонки с номером DataCol. Ячейка задается прямоугольником Rect на канве сетки. Параметр State определяет состояние ячейки после перерисовки. Параметр Column содержит экземпляр класса колонки, которой принадлежит ячейка |
Procedure DefaultDrawDataCell (const Rect: TRect; Field: TField; State: TGridDrawState) ; |
Pu |
Перерисовывает текст в ячейке колонки, определяемой параметром Field, содержащим связанный с колонкой объект поля. Ячейказадается прямоугольником Rect на канве сетки. Параметр State определяет состояние ячейки после перерисовки |
procedure DefaultHandler(var Msg); override; |
Pu |
Обработчик событий. Используется для изменения поведения компонента. Для этого метод необходимо перекрыть |
function ExecuteAction(Action: TBasicAction): Boolean; override; |
Pu |
Выполняет действие, заданное параметром Action, no отношению к данному компоненту |
procedure ShowPopupEditor(Colum n: TColuinn; X: Integer = Low(Integer); Y: Integer=Low(Integer)) ;dynamic; |
Pu |
Открывает набор данных, связанный с передаваемой параметром Column колонкой в новом окне. Работает только для типов данных: абстрактный и набор данных. Параметры X и Y определяют положение нового окна |
function ValidFieldIndex(Field Index: Integer): Boolean; |
Pu |
Возвращает True, если столбец сетки с номером Fieldlndex связан с полем набора данных |
type TGridCoord =record X: Longint; Y: Longint; end; function MouseCoordfX, Y: Integer): TGridCoord; |
Pu
|
Возвращает номера строки и столбца, соответствующих ячейке, которой принадлежат экранные координаты х и Y |
Методы-обработчики событий |
||
Type TDBGridClickEvent = procedure (Column: TColumn) of object; property OnCellClick: TDBGridCiickEvent; |
Pb
|
Вызывается при щелчке мышью на ячейке сетки. Параметр column содержит колонку, которой принадлежит ячейка |
property OnColEnter: TNotifyEvent; |
Pb
|
Вызывается при переносе фокуса на новую колонку сетки |
property OnColExit: TNotifyEvent; |
Pb |
Вызывается перед переносом фокуса из текущей колонки |
type TMovedEvent = procedure (Sender: TObject; Fromlndex, Tolndex: Longint) of object; |
Pb
|
Вызывается при переносе колонки в сетке на новое место при помощи мыши. Параметр Fromlndex возвращает номер старого положения колонки. Параметр Tolndex возвращает номер нового положения колонки |
property OnColumnMoved: TMovedEvent ; |
|
|
type TDrawColunmCellEvent = procedure (Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState) of Object; |
Pb
|
Вызывается при перерисовке ячейки. Параметр Recr. определяет ячейку по координатам прямоугольника на канве. Параметр DataCol возвращает номер колонки в сетке. Параметр Column содержит объект колонки. Параметр State возвращает состояние колонки. |
property OnDrawColumnCell: TDrawColumnCellEvent; |
|
|
Методы-обработчики событий |
||
type TDrawDataCellEvent = procedure (Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState) of object; property OnDrawDataCell: TDrawDataCellEvent; |
Pb
|
Вызывается при перерисовке ячейки, перед обработчиком OnDrawColumnCell, если свойство сетки Columns. State =csDefault. Этот метод лучше не применять, так как он используется только для обеспечения обратной совместимости |
property OnEditButtonClick: TNotifyEvent; |
Pb |
Вызывается при щелчке мышью на кнопке в ячейке сетки |
Type TDBGridClickEvent = procedure (Column: TColumn) of object; |
Pb |
Вызывается при щелчке мышью на заголовке колонки. Колонка определяется параметром Column |
property OnTitleClick: TDBGridClickEvent; |
|
|
В работе компонента TDBGrid важную роль играет класс TColumn, который инкапсулирует свойства колонки или столбца сетки (табл. 18.3). Его основным назначением является правильное отображение данных из поля набора данных, связанного с этой колонкой. Поэтому объект колонки обладает свойствами и методами, которые позволяют произвольным образом задавать параметры отображения данных (цвет, шрифт, ширину и т. д.). Первоначальные значения берутся из связанных с колонками полей. Измененные свойства можно восстановить при помощи группы специальных методов (DefaultColor, DefaultFont и др.).
Свойство Assignedvalues позволяет в любой момент определить, какие первоначальные настройки были изменены.
За отображение заголовка колонки отвечает свойство Title, представляющее собой ссылку на экземпляр объекта TCoiumnTitie. Здесь можно задать текст заголовка, параметры шрифта текста заголовка и цвет фона заголовка. По умолчанию текст заголовка берется из свойства nispiayLabel объекта TField (гл. 17).
Каждой колонке можно придать список, который разворачивается при щелчке на кнопке в активной ячейке колонки. Выбранное в списке значение автоматически заносится в ячейку. Для реализации этой возможности.
применяется свойство pickList типа TStrings. Достаточно лишь заполнить список значениями во время разработки или выполнения (рис. 18.3).
Рис. 18.3. Список колонки в компоненте TDBGrid
Таблица 18.3. Свойства и методы класса TColumn
Объявление |
Тип |
Описание |
Свойства |
||
property Alignment: TAlignment; |
Рb |
Определяет выравнивание данных в колонке |
type TColumnValue = (cvColor, cvWidth, cvFont, cvAlignment, cvReadOnly, cvTitleColor, cvTitleCaption, cvTitleAlignment, cvTitleFont, cvImeMode, cvImeName) ; TColumnValues - set of TColumnValue; property AssignedValues: TColumnValues; |
Ro
|
Возвращает набор атрибутов колонки, которые были изменены по сравнению с первоначальными
|
type TColumnButtonStyle = (cbsAuto, cbsEllipsis, cbsNone) ; property ButtonStyle: TColumnButtonStyle; |
Pb
|
Задает способ редактирования данных в колонке. cbsAuto — кнопка в редактируемой ячейке появляется, если связанное поле является полем синхронного просмотра cbsEllipsis — кнопка в редактируемой ячейке появляется всегда, щелчок на кнопке вызывает обработчик OnEditButtonClick cbsNone — при редактировании ячейки кнопка не появляется |
property Color: TColor; |
Pb |
Цвет фона колонки |
property DisplayName: string; |
Pu |
Название колонки в списке Редактора столбцов |
Property DropDownRows:Cardinals; |
Pb |
Определяет число строк разворачивающегося списка ячейки |
property Expandable: Boolean; |
Pu |
В значении True разрешает показ связанных с полем колонки дочерних полей абстрактного, ссылочного типов и массивов |
property Expanded: Boolean; |
Pb |
При значении True каждое дочернее поле отображается в новой колонке. При значении False дочерние поля отображаются через точку с запятой и недоступны для редактирования. |
property FieldName: string; |
Pb |
Название поля, связанного с колонкой |
property Font: TFont; |
Pb |
Шрифт данных в колонке |
property Grid: TCustomDBGrid; |
Ro |
Определяет сетку, содержащую эту колонку |
type TImeMode = (imDisable, imClose, imOpen, imDontCare, imSAlpha, imAlpha, imHira, imSKata, imKata, imChinese, imSHanguel, imHanguel); property ImeMode: TTTTioMficlp; |
Pb
|
Определяет способ ввода символов. Используется для ввода иероглифов
|
type TImeName = type string; |
Pb |
Определяет имя редактора способа ввода символов |
property ImeName: TImeName; |
|
|
property ParentColumn: TColumn; |
Ro |
Определяет колонку-владельца текущей колонки. Используется для дочерних полей |
property PickList: TStrings; |
Pb |
Содержит разворачивающийся список, используемый при редактировании данных |
property PopupMenu: TPopupMenu; |
Pb |
Связывает с колонкой всплывающее меню |
property Showing: Boolean- |
Ro |
Возвращает True, если колонка видима |
property Title: TColunmTitie; |
Pb |
Задает текст заголовка и его параметры |
property Visible: Boolean; |
Pb |
Задает видимость колонки |
property Width: Integer; |
Pb |
Задает ширину колонки в пикселах |
Методы |
||
procedure Assign(Source: TPersistent) ; override; |
Pu |
Копирует колонку Source в текущую колонку |
function DefaultAlignment: TAlignment; |
Pu |
Возвращает первоначальное значение выравнивания колонки |
function DefaultCoior: TColor; |
Pu |
Возвращает первоначальный фоновый цвет колонки |
function DefaultFont: TFont; |
Pu |
Возвращает первоначальный шрифт данных в колонке |
type TimeMode= (imDisable, imClose, imOpen, imDontCare, imSAlpha, iroAlpha, imHira, imSKata, imKata, imChiriese, imSHanguel, imHanguel); |
Pu |
Возвращает первоначальный способ ввода символов |
function De faultImeMode: TImeMode; |
|
|
type TImeName = type string; |
Pu |
Возвращает первоначальное имя редактора способа ввода символов |
function DefaultImeName: TImeName; |
|
|
function DefaultReadOnly: Boolean; |
Pu |
Возвращает первоначальный режим редактирования данных |
function DefaultWidth: Integer; |
Pu |
Возвращает первоначальную ширину колонки в пикселах |
function Depth: Integer; |
Pu |
Возвращает число непосредственных предков колонки |
procedure RestoreDefaults ; virtual; |
Pu |
Восстанавливает первоначальные настройки колонки |
При работе с сеткой все операции с отдельными колонками осуществляются при помощи экземпляра класса TDBGridCoiumns, который инкапсулирует список объектов колонок (свойство columns компонента TDBGrid). Доступ к колонкам осуществляется при помощи свойства items. Нумерация колонок начинается с нуля.
При помощи свойств и методов класса TDBGridCoiumns можно изменять настройки полей компонента TDBGrid во время выполнения (табл. 18.4).
Свойство state определяет способ создания колонок. Его значение устанавливается автоматически. При создании колонок для всех полей сразу (кнопка Add All Fields Редактора столбцов) устанавливается значение csDefault. При любом ручном изменении свойств устанавливается значение csCustomized. При программном изменении значения свойства во время выполнения все существующие колонки удаляются.
Все данные из существующих колонок можно сохранить в файле или потоке при помощи методов SaveToFile и saveToStream. а затем загрузить их обратно методами LoadPromFile И LoadFromStream.
Таблица 18.4. Свойства и методы класса TDBGridCoiumns
Объявление | Тип | Описание | |
property Grid: TCustomDBGrid; | Ro | Возвращает ссылку на сетку, владеющую данным объектом | |
property Items[Index: Integer]: TColumn default; |
Pu |
Индексный список объектов колонок сетки |
|
type TDBGridColumnsState = (csDefault, csCustomized); property State: TDBGridColumnsState; |
Pu |
Определяет способ создания колонок сетки. csDefault — колонки создаются динамически, с параметрами, соответствующими связанным полям csCustomized — параметры колонок определены разработчиком и могут отличаться от параметров полей |
|
property Count: Integer; |
Pu |
Возвращает общее число колонок |
|
Методы |
|||
function Add: TColumn; |
Pu |
Добавляет новый объект TColumn |
|
procedure LoadFromFile(const Filename: string); |
Pu |
Загружает данные в объект из файла FileName |
|
procedure LoadFromStream(S: TStream); |
Pu |
Загружает данные в объект из потока s |
|
procedure RebuildColumns; |
Pu |
Удаляет существующие колонки и создает новые, основываясь на параметрах полей набора данных |
|
procedure RestoreDefsuits; |
Pu |
Восстанавливает первоначальные настройки колонок |
|
procedure SaveToFile(const Filename: strings- |
Pu |
Сохраняет данные из колонок в файле FileName |
|
procedure SaveToStreamfS: TStream); |
Pu |
Сохраняет данные из колонок в потоке s |
Компонент TDBCtrlGrid
Компонент TDBCtrlGrid внешне напоминает сетку, но никак не связан с классом TCustomDBGrid, а происходит напрямую от класса TWinControl.
Этот компонент позволяет отображать данные в строках в произвольной форме. Компонент представляет собой набор панелей, каждая из которых служит платформой для размещения Данных отдельной записи набора данных. На панели могут размещаться любые компоненты отображения данных, предназначенные для работы с отдельным полем. С каждым таким компонентом можно связать нужное поле набора данных. При открытии набора данных в компоненте TDBCtrlGrid на каждой .новой панели создается набор компонентов отображения данных, аналогичный тому, который был создан на одной панели во время разработки.
На панель можно переносить только те компоненты отображения данных, которые показывают значение одного поля для единственной записи набора данных. Нельзя использовать компоненты TDBGrid, TDBCtrlGrid, TDBRichEdit, TDBListBox,TDBRadioGroup,TDBLookupListBox.
После того как для компонента TDBCtrlGrid задано значение свойства DataSource (табл. 18.5), все переносимые на панель компоненты отображения данных автоматически связываются с указанным компонентом TDaiaSource. Самостоятельное задание свойства DataSource для дочерних компонентов отображения данных не допускается. В них требуется определить только поля.
Компонент может отображать панели в одну или несколько колонок. Для задания числа колонок панелей используется свойство Coicount. Число видимых строк панелей определяется свойством RowCount. Вертикальное или горизонтальное размещение колонок панелей зависит от значения свойства
Orientation.
При использовании нескольких колонок панелей курсор перемещается по колонке сверху вниз с последующим переходом на следующую колонку. Направление движения курсора не зависит от значения свойства
Orientation.
Размеры одной панели определяются свойствами PanelHeiqht И PanelWidth.
Они взаимосвязаны с размерами самого компонента. При изменении значений свойств panelHeight и PanelWidth размеры компонента изменяются таким образом, чтобы в нем помещалось указанное в свойствах Coicount и RowCount число панелей и наоборот.
Не рекомендуется размещать на панели компоненты товмето и TDBimage, так как это может привести к значительному снижению производительности.
Таблица 18.5. Свойства и методы компонента TDBCtrlGrid
Объявление |
Тип |
Описание |
property AllowDelete: Boolean; |
Pb |
Разрешает или запрещает удаление текущей записи |
property Allowlnsert: Boolean; |
Pb |
Разрешает или запрещает вставку новой записи |
property Canvas: TCanvas; |
Ro |
Канва компонента |
property ColCount: Integer; |
Pb |
Определяет число колонок с панелями |
property EditMode: Boolean; |
Pu |
Разрешает или запрещает редактирование данных |
type TDBCtrlGridOrientatio n - (goVertical, goHorizontal) ; property Orientation: TDBCtrlGridOrientation; |
Pb
|
Определяет порядок следования записей по горизонтали или по вертикали |
type TDBCtrlGridBorder = (gbNone, gbRaised); property PanelBorder: TDBCtrlGridBorder; |
Pb
|
Определяет способ отображения границы панели |
property PanelCount: Integer; |
Ro |
Содержит число видимых одновременно панелей |
property PanelHeight: Integer; |
Pb |
Определяет высоту панелей в пикселах |
property Panellndex: Integer; |
Pu |
Определяет индекс панели текущей записи |
property PanelWidth: Integer; |
Pb |
Определяет ширину панелей в пикселах |
property RowCount: Integer; |
Pb |
Определяет число строк видимых панелей |
property SelectedColor: TColor; |
Pb |
Определяет фоновый цвет панели текущей записи |
property ShowFocus: Boolean; |
Pb |
Разрешает или запрещает выделение вокруг панели текущей записи |
Методы |
||
type TDBCtrlGridKey = (gkNull, gkEditMode, gkPriorTab, |
|
Выполняет операцию, заданную при помощи параметра Key. |
gkNextTab, gkLeft, gkRight, gkUp, gkDown, gkScrolIUp, gkScroll Down, gkPageUp, gkPageDown, gkHome, gkEnd, gklnsert, gkAppend, gkDelete, gkCancel) ; procedure DoKey(Key: TDBCtrlGridKey) ; procedure KeyDownfvar Key: Word; Shift: TShiftState); override; |
Доступны операции навигации по записям, перевода в режим редактирования, вставки, удаления записей, отмены изменений. Используется при нажатии клавиши для трансляции кодов клавиш |
|
Методы-обработчики событий |
||
type TPaintPanelEvent = procedure(DBCtrlGrid: TDBCtrlGrid; Index: Integer) of objects- property OnPaintPanel: TPaintPanelEvent; |
Вызывается при перерисовке панели. Параметр Index соответствует индексу панели |
Связанные таблицы
В рамках одного проекта таблицы БД можно связывать отношениями "один ко многим" и "многие ко многим", отношения устанавливаются обязательно между индексированными полями двух таблиц.
При создании отношений в качестве главной таблицы можно использовать набор данных запроса SQL (компонент TQuery) или набор данных таблицы (компонент TTabie). Для задания подчиненной таблицы можно использовать только наборы данных на основе компонента TTabie.
Отношение "один ко многим"
Для установления отношения "один ко многим" в наборе данных предназначены два свойства — MasterSource и MasterFieids, которые задаются для подчиненной таблицы. Набор данных главной таблицы не требует никаких дополнительных настроек и заданная связь будет работать только при перемещениях по записям главной таблицы.
Свойство MasterSource определяет компонент TDataSource, который связан с главной таблицей.
Затем при помощи свойства MasterFields необходимо установить отношения между полями главной и подчиненной таблицы. В нем содержится имя индексированного поля, по которому устанавливается связь. Если таких полей несколько, их имена разделяются точкой с запятой. При этом не все поля, входящие в индекс, обязаны участвовать в создании отношения.
Для задания свойства MasterFields можно использовать Редактор связей полей (Field Link Designer), который вызывается щелчком на кнопке в поле редактирования этого свойства в Инспекторе объектов .
Здесь в разворачивающемся списке Available Indexes выбирается требуемый индекс для подчиненной таблицы. После этого в списке Detail Fields появляются имена всех полей, входящих в этот индекс. В списке Master Fields отображаются все поля главной таблицы.
Теперь требуется создать связи между полями. Для этого в левом списке выбирается поле подчиненной таблицы, а затем соответствующее ему поле главной таблицы в правом списке. После этого активизируется кнопка Add, щелчок на которой создает отношение по двум полям главной и подчиненной таблиц. Созданная связь отображается в списке Joined Fields.
После создания связи по индексированным полям данный индекс становится текущим для набора данных. При этом, в зависимости от типа СУБД, автоматически заполняется свойство IndexName или IndexFieldNames.
Уже созданные связи можно удалить. Кнопка Delete удаляет выбранную связь, кнопка Clear удаляет все связи.
После создания связей между полями отношение "один ко многим" считается установленным. Теперь достаточно открыть оба набора данных, чтобы увидеть работу отношения.
Рис. 18.4. Главная форма проекта DemoJoins
В качестве примера рассмотрим проект DemoJoins (рис. 18.4), в котором связываются таблицы из демонстрационной базы данных DBDEMOS.
Таблица Customers представлена в наборе данных компонента custTabie, она содержит данные о покупателях. Таблица Orders представлена в наборе данных компонента ОrdTable, она содержит данные о заказах. Таблица Employee представлена в наборе данных компонента EmpTabie, она содержит данные о продавцах.
Приложение DemoJoins не содержит дополнительного исходного кода. Все отношения между таблицами заданы при помощи Инспектора объектов.
Отношение "один ко многим" задано между таблицами покупателей (Customers) и заказов (Orders). Таблица покупателей является главной. Для создания отношения установлены следующие значения свойств компонента OrdTable (подчиненная таблица).
Свойство MasterSource должно указывать на компонент custsource, связанный с набором данных CustTabie.
Свойство MasterFieids указывает на поле custNo таблицы Customers. В наборе данных ordTable включен вторичный индекс на основе поля
CustNo (indexName = 'CustNo').
Таким образом, две таблицы связаны отношением "один ко многим" по индексированным полям CustNo (номер покупателя). В результате, при перемещении по записям таблицы покупателей, в таблице заказов будут показаны только те заказы, которые относятся к текущему покупателю.
Отношение "многие ко многим"
Отношение "многие ко многим" отличается тем, что подчиненная таблица еще раз связывается в качестве главной с другой подчиненной таблицей аналогичной последовательностью действий, как и в отношении "один ко многим".
В приложении DemoJoins отношением "многие ко многим" связаны таблицы заказов (Orders) и продавцов (Employee). Таблица заказов уже работает в отношении "один ко многим" в качестве подчиненной.
В наборе данных EmpTable заданы следующие свойства. Свойство MasterSource указывает на компонент Empsource.
Свойство MasterFields содержит имя поля EmpNo, по которому осуществляется связь между таблицами. Для подчиненной таблицы поле EmpNo является первичным
Навигация по набору данных
Перемещение или навигация по записям набора данных может осуществляться несколькими путями. Например, в компонентах TDBGrid и TDBCtriGrid, которые отображают сразу несколько записей набора данных, можно использовать клавиши вертикального перемещения курсора или вертикальную полосу прокрутки.
Но что делать, если на форме расположены только компоненты, отображающие одно поле только текущей записи набора данных (TDBEdit, TDBComboBox и т. д.)? Очевидно, что в этом случае на форме должны быть расположены дополнительные элементы управления, отвечающие за перемещение по записям.
Аналогично, ни один компонент отображения данных не имеет встроенных средств для создания и удаления записей целиком.
Для решения указанных задач и предназначен компонент TDBNavigator, который представляет собой совокупность управляющих кнопок, выполняет операции навигации по набору данных и модификации записей целиком.
Компонент TDBNavigator при помощи свойства DataSource связывается с компонентом TDataSource и через него с набором данных. Такая схема позволяет обеспечить изменение текущих значений полей сразу во всех связанных с TDataSource компонентах отображения данных. Таким образом,
TDBNavigator только дает команду на выполнение перемещения по набору данных или другой управляющей операции, а всю реальную работу выполняют BDE, компонент набора данных и компонент TDataSource. Компонентам отображения данных остается только принять новые данные от своих полей.
Работа навигатора самым тесным образом связана с курсорами BDE. Курсор представляет собой объект, который содержит текущую запись набора данных и умеет загружать в себя новые записи, одновременно инициируя процесс сохранения сделанных в текущей записи изменений.
Рис. 18.5. Назначение кнопок компонента TDBNavigator
Компонент TDBNavigator содержит набор кнопок (рис. 18.5), каждая из которых отвечает за выполнение одной операции с набором данных. Всего имеется 10 кнопок, разработчик может оставить в наборе любое количество кнопок в любом сочетании. Видимостью кнопок управляет свойство visibleButtons:
type
TNavigateBtn - (nbFirst, nbPrior, nbNext, nbLast, nblnsert, nbDelete, nbEdit, nbPost, nbCancel, nbRefresh);
TButtonSet = set of TNavigateBtn;
property VisibleButtons: TButtonSet;
Каждый элемент типа TNavigateBtn представляет одну кнопку, их назначение описывается ниже.
Самой критичной к возможной потере данных вследствие ошибки является операция удаления записи, поэтому при помощи свойства coiifj rmDelete можно включить механизм контроля удаления. При каждом удалении записи нужно будет дать подтверждение выполняемой операции.
Нажатие любой кнопки можно эмулировать программно при помощи метода BtnClick.
В случае необходимости выполнения дополнительных действий при щелчке на любой кнопке можно воспользоваться обработчиками событий BeforeAction и OnClick, в которых параметр Button определяет нажатую кнопку (табл. 18.6).
Таблица 18,6. Свойства и методы компонента TDBNavigaiur
Объявление |
Тип |
Описание |
Свойства |
||
Property ConfirmDelete: Boolean; |
Pb |
Включает или отключает подтверждение удаления записи |
Property Hint5: Tstrings; |
Pb |
Содержит список подсказок для каждой кнопки |
Property Flat: Boolean; |
Pb |
Определяет внешний вид кнопок компонента |
Type |
Pb |
Список видимых кнопок |
TnavigateBtn = (nbFirst, nbPrior, nbNext, nbLast, nblnsert, nbDelete, nbEdit, nbPost, nbCancel, nbRefresh) ; TbuttonSet = set of TnaviqateBtn; Property VisibleButtons: TbuttonSet; |
|
|
Методы |
||
Procedure BtnCiick(Index: TnavigateBtn); |
Pu |
Эмулирует щелчок на кнопке index |
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); |
Pu |
Задает положение (параметры ALeft, ATop) и размер компонента (параметры AWidth, AHeight) |
Методы-обработчики событий |
||
ENavClick - procedure (Sender: TObject; Button: TNavigateBtn) of object; property BeforeAction: ENavClick; |
Pb |
Выполняется при щелчке на кнопке Button, перед выполнением операции, связанной с кнопкой |
ENavClick = procedure (Sender: TObject; Button: TNavigateBLn) of object; property OnClick: ENavClick; |
Pb |
Выполняется при щелчке на кнопке Button, после выполнения операции, связанной с кнопкой |
Представление отдельных полей
Большинство компонентов отображения данных предназначено для представления данных из отдельных полей. Для этого все они имеют свойство DataField, которое указывает на требуемое поле набора данных.
В зависимости от типа данных поля, могут использоваться различные компоненты. Для большинства стандартных полей используются компоненты
TDBText, TDBEdit,TDBComboBox, TDBListBox.
Данные в формате Memo отображаются компонентами то вместо и
TDBRichEdit.
Для показа изображений предназначен компонент TDBimage.
Компонент TDBText
Этот компонент представляет собой статический текст, который отображает текущее значение некоторого поля связанного набора данных. При этом данные можно просматривать в режиме "только для чтения".
Непосредственным предком компонента является класс TCustoinLabel, по- этому он очень похож на компонент TLabel.
При использовании компонента следует обратить внимание на возможную длину отображаемых данных. Для предотвращения обрезания текста можно использовать свойства AutoSize и Wordwrap.
Компонент TDBEdit
Компонент представляет собой стандартный однострочный текстовый редактор, в котором отображаются и изменяются данные из поля связанного набора данных.
Прямой предок компонента — класс TCustomMaskEdit, который также является прямым предком компонента TEdit.
Компонент может осуществлять проверку редактируемых данньк по заданной для поля маске (шаблону). Непосредственно для редактора задать маску нельзя, так как содержащее маску свойство EditMask в классе TCustomMaskEdit является защищенным, а в TDBEdit не перекрыто. Тем не менее, механизм контроля полностью унаследован. Саму же маску можно задать в связанном с редактором поле. Объект TField имеет собственное свойство EditMask, которое и используется при проверке данных в редакторе (гл. 17).
Проверка редактируемого текста на соответствие шаблону осуществляется методом validateEdit после каждого введенного или измененного символа. В случае ошибки генерируется исключение validateError и курсор устанавливается на первый ошибочный символ.
В компоненте можно использовать буфер обмена. Это делается средствами операционной системы пользователем или программно при помощи методов CopyToClipboard, CutToClipboard, PasteFromClipboard.
Компонент TDBCheckBox
Компонент представляет собой почти полный аналог обычного флажка (компонент TCheckBox) и предназначен для отображения и редактирования любых данных, которые могут иметь только два значения. Это может быть логический тип данных или любые строковые значения, но поле может принимать значения только из двух строк.
Предопределенные значения задаются свойствами valuechecked и vaiueUnchecked. По умолчанию они имеют значения True и False. Этим свойствам можно также присваивать любые строковые значения, причем одному свойству можно назначить несколько возможных значений, разделенных точкой с запятой.
Включение флажка происходит, если значение поля набора данных совпадает со значением свойства valuechecked (единственным или любым из списка). Если же флажок включил пользователь, то значение поля данных приравнивается к единственному или первому в списке значению свойства ValueChecked. Аналогичные действия происходят и со свойством ValueUnchecked.
Компонент TDBRadioGroup
Компонент представляет собой стандартную группу переключателей, состояние которых зависит от значений поля связанного набора данных. В поле можно передавать фиксированные значения, связанные с отдельными переключателями в группе.
Если текущее значение связанного поля соответствует значению какого-либо переключателя, то он включается. Если пользователь включает другой переключатель, то связанное с переключателем значение заносится в поле.
Возможные значения, на которые должны реагировать переключатели в группе, заносятся в свойство values при помощи специального редактора в Инспекторе объектов или программно при помощи методов класса TStrings. Каждому элементу свойства values соответствует один переключатель (порядок следования сохраняется).
Свойство items содержит список поясняющих надписей для переключателей группы. Если для какого-либо переключателя нет заданного значения, но есть поясняющий текст, то такой переключатель включается при совпадении значения связанного поля с поясняющим текстом.
Текущее значение связанного поля содержится в поле value.
Компонент TDBListBox
Компонент отображает текущее значение связанного с ним поля набора данных и позволяет изменить его на любое фиксированное из списка. Функционально компонент ничем не отличается от компонента TListBox. Значение поля должно совпадать с одним из элементов списка.
Специальных методов компонент не содержит.
Компонент TDBComboBox
Компонент отображает текущее значение связанного с ним поля набора данных в строке редактирования, при этом значение поля должно совпадать с одним из элементов выпадающего списка. Текущее значение можно изменить на любое фиксированное из списка компонента. Функционально компонент ничем не отличается от компонента ТСоmbовох, представляющего собой комбинированный список.
Компонент может работать в пяти различных стилях, которые определяются cвойством Style.
Специальных методов компонент не содержит.
Компонент TDBMemo
Компонент представляет собой обычное поле редактирования, к которому подключается поле с типом данных Memo или BLOB. Основное его преимущество — возможность одновременного просмотра и редактирования нескольких строк переменной длины. Компонент может отображать только строки, которые целиком видны по высоте.
В компоненте можно использовать буфер обмена при помощи стандартных средств операционной системы или унаследованными от предка TcustomMemo методами CopyToClipBoard, CutToClipBoard, PasteFromClipBoard.
Для ускорения навигации по набору данных при отображении полей типа BLOB можно использовать свойство AutoDispiay. При значении True любое новое значение поля автоматически отображается в компоненте. При значении False новое значение появляется только после двойного щелчка на компоненте или после нажатия клавиши <Enter> при активном компоненте.
Метод LoadMemo используется автоматически при загрузке значения поля, если свойство AutoDispiay = False.
Поведением компонента при работе со слишком длинными строками можно управлять при помощи свойства wordwrap. При значении True слишком длинная строка сдвигается влево при перемещении текстового курсора за правую границу компонента. При значении False остаток длинной строки переносится на новую строку, при этом реально новая строка в данных не создается.
Компонент TDBImage
Компонент предназначен для просмотра изображений, хранящихся в базах данных в графическом формате.
Редактировать изображения можно только в каком-либо графическом редакторе, перенося исходное и измененное изображения при помощи буфера обмена. Это делается средствами операционной системы пользователем или
Программно при помощи методов CopyToClipboard, CutToClipboard, PasteFromClipboard.
Визуализация изображения осуществляется при помощи свойства picture, которое представляет собой экземпляр класса TPicture.
Также можно полностью заменить существующее изображение или сохранить новое в новой записи набора данных. Для этого используются методы свойства picture.
Свойство AutoDisplay позволяет управлять процессом загрузки новых изображении из набора данных в компонент. При значении True любое новое значение поля автоматически отображается в компоненте. При значении False новое значение появляется только после двойного щелчка на компоненте или после нажатия клавиши <Enter> при активном компоненте.
Для ускорения просмотра изображений можно использовать свойство QuickDraw, которое задает используемую изображением палитру. При значении True применяется стандартная системная палитра. В результате уменьшается время загрузки изображения, но может ухудшиться и качество изображения, в некоторых случаях до полного искажения. При значении False используется собственная палитра изображения и процесс загрузки замедляется.
Компонент TDBRichEdit
Компонент предоставляет возможности полноценного текстового редактора для просмотра и изменения текстовых данных, хранящихся в связанном поле набора данных. Поле должно содержать информацию о форматировании текста.
Внешне компонент ничем не отличается от поля редактирования, поэтому о реализации доступа к гораздо более богатым возможностям редактора через интерфейс пользователя должен позаботиться разработчик. Для этого можно использовать дополнительные элементы управления.
Синхронный просмотр данных
При разработке приложений для работы с базами данных часто возникает необходимость в связывании двух наборов данных по ключевому полю. Например, в таблице Orders (содержит данные о заказах) демонстрационной базы данных DBDEMOS имеется поле CustNo, которое содержит идентификационный номер покупателя. Под этим же номером в таблице Customers хранится информация о покупателе (адрес, телефон, реквизиты и т. д.). При разработке пользовательского интерфейса приложения баз данных необходимо, чтобы при просмотре перечня заказов в форме приложения отображались не идентификационные номера покупателей, а их параметры.
Таким образом, в наборе данных заказов вместо поля номера покупателя должно появиться поле имени покупателя из таблицы Customers. Механизм связывания полей из различных наборов данных по ключевому полю называется синхронным просмотром. В рассмотренном примере ключевым является поле CustNo из таблицы Customers, а выбор конкретного наименования производится по совпадению значений ключевого поля и заменяемого- поля из исходного набора данных Orders. Причем необходимо, чтобы в таблице
Customers поле custNo было уникальным (составляло первичный или вторичный ключ).
Таблицу, в которой расположено поле, значения которого замешаются на синхронные, будем называть исходной таблицей (это таблица Orders).
Таблицу, содержащую ключевое поле и поле данных для синхронного просмотра будем называть таблицей синхронного просмотра (таблица Customers).
В Delphi механизм синхронного просмотра реализован на уровне отдельных полей и компонентов.
В наборе данных динамически можно создать специальное поле синхронного просмотра, которое будет автоматически замещать одно значение другим в зависимости от значения ключевого поля. Такое поле можно связать с любым рассмотренным выше компонентом отображения данных (гл. 17).
Помимо простого синхронного просмотра данных, может возникнуть задача редактирования данных в аналогичной ситуации. Для этого предназначены специальные компоненты синхронного просмотра данных, которые позволяют, например, выбирать покупателя из списка, а изменится при этом номер покупателя в наборе данных заказов. Использование таких компонентов делает пользовательский интерфейс значительно более удобным и наглядным. В VLC Delphi есть два таких компонента: TDBLookupListBox и TDBLookupComboBox.
На странице Win 3.1 Палитры компонентов имеются еще два компонента: TDBLokupList и TDBLookupCombo. Они обладают тем же набором функций, используются для обеспечения совместимости с приложениями, созданными в среде разработки Delphi 1, и поэтому здесь не рассматриваются.
Механизм синхронного просмотра
Непосредственным предком компонентов синхронного просмотра данных является класс TDBLookupControl, который инкапсулирует список значений для просмотра и сам механизм синхронного просмотра.
Как и в любом другом компоненте отображения данных, в компонентах синхронного просмотра должны присутствовать средства связывания с требуемым полем некоторого набора данных. Это уже известные свойства DataSource — для задания набора данных через компонент TDatasource и DataFieid — для определения требуемого поля набора данных. Для синхронного просмотра следует выбирать такое поле, значения которого не дают пользователю полной информации об объекте и совпадают с ключевым полем в таблице синхронного просмотра. Название этого поля может не совпадать с названием ключевого поля, но типы данных должны быть одинаковыми.
При проектировании баз данных желательно, чтобы такие поля все же носили одинаковые названия.
Теперь необходимо задать таблицу синхронного просмотра, ключевое поле и , поле синхронного просмотра.
Набор данных, содержащий указанные поля, определяется через соответствующий компонент TDataSource В свойстве ListSource.
Ключевое поле задается свойством KeyField. Во время работы компонента в свойстве Keyvalue содержится текущее значение, которое связывает между собой два набора данных.
Поле синхронного просмотра определяется свойством ListField. Здесь можно задавать сразу несколько полей, которые будут отображаться в компоненте синхронного просмотра. Названия полей разделяются точкой с запятой. Если свойство не определено, то в компоненте будут отображаться значения ключевого поля. Свойство ListFieidindex служит для выбора основного поля из списка. Дело в том, что компоненты синхронного просмотра поддерживают механизм наращиваемого поиска, который позволяет быстро находить нужное значение в больших списках. Свойство ListFieidindex определяет, какое поле используется при наращиваемом поиске. В компоненте TDBiookupComboBox свойство ListFieidindex также определяет, какое поле будет передано в строку редактирования (табл. 18.7).
Таблица 18.7. Основные свойства, включающие механизм синхронного просмотра
Объявление |
Тип |
Описание |
property KeyField: string; |
Pb |
Ключевое поле таблицы синхронного просмотра |
property KeyVaiue: Variant; |
Pu |
Текущее значение ключевого поля |
property ListField: string; |
Pb |
Поле или список полей синхронного просмотра в таблице синхронного просмотра |
property ListFieidindex: Integer; |
Pb |
Номер основного поля синхронного просмотра (используется, когда свойство ListField содержит список полей) |
property ListSource: TdataSource; |
Pb |
Указывает на компонент TDataSource, связанный с таблицей синхронного просмотра |
В качестве примера рассмотрим приложение DemoLookup (рис. 18.6), в котором с набором данных таблицы Orders из базы данных DBDEMOS связаны компоненты TDBGrid и TDBLookupComboBox. Во втором компоненте при перемещении по записям набора данных отображается имя покупателя, оформившего текущий заказ.
Рис. 18.6. Главная форма проекта DemoLookup
Ключевые свойства компонента настроены следующим образом.
Компонент TDBLookupListBox
Компонент представляет собой список значений поля синхронного просмотра для поля, заданного свойством DataField, из набора данных Datasource. Его основное назначение — автоматически устанавливать соответствие между полями двух наборов данных по одинаковому значению заданного поля исходной таблицы и ключевого поля таблицы синхронного просмотра. В списке синхронного просмотра отображаются возможные значения для редактирования поля основной таблицы.
По своим функциональным возможностям компонент совпадает с компонентом TDBListBox.
Компонент TDBLookupComboBox
Компонент представляет собой комбинированный список значений поля синхронного просмотра для поля, заданного свойством DataFieid, из набора данных Datasource. Его основное назначение — автоматически устанавливать соответствие между полями двух наборов данных по одинаковому значению заданного поля исходной таблицы и ключевого поля таблицы синхронного просмотра. В списке синхронного просмотра отображаются возможные значения для редактирования поля основной таблицы.
По своим функциональным возможностям компонент совпадает с компонентом TDBComboBox.
Графическое представление данных
Для представления данных из некоторого набора данных в виде графиков различных видов предназначен компонент TDBChart (см. табл. 18.7). В нем можно одновременно показывать графики для нескольких полей данных. Графики строятся на основе всех имеющихся в наборе данных значений полей. Функционально компонент ничем не отличается от компонента TChart.
Настройка параметров компонента осуществляется специальным редактором, который можно открыть двойным щелчком на перенесенном на форму компоненте.
Здесь мы не будем подробно останавливаться на богатейших изобразительных возможностях этого компонента, рассмотрим только процесс подключения к нему набора данных и построение графиков.
Основой любого графика в компоненте TDBChart является так называемая серия, свойства которой представлены классом TChartSeries. Для того чтобы построить график значений некоторого поля набора данных, необходимо выполнить следующие действия, большинство из которых выполняется в специализированном редакторе компонента.
Рис. 18.7. Специализированный редактор компонента TDBChart
Редактор имеет две главные страницы — Chart и Series. Страница Chart содержит многостраничный блокнот и предназначена для настройки параметров самого графика. Страница Series также содержит многостраничный блокнот и используется для настройки серий значений данных.
Для создания новой серии необходимо в редакторе перейти на главную страницу Chart, а на ней открыть страницу Series (рис. 18.8). На этой странице нужно щелкнуть на кнопке Add, а затем в появившемся диалоге выбрать тип серии. После этого в списке на странице Series появляется строка новой серии. Здесь можно переопределить тип, цвет и видимость серии, щелкнув на соответствующей зоне строки.
Все остальные страницы блокнота на главной странице Chart предназначены для настройки параметров графика.
Теперь необходимо перейти на главную страницу Series и на ней из списка названий серий выбрать необходимую. После этого на странице Data Source из списка выбирается строка DataSet. После этого в появившемся списке DataSet выбирается нужный набор данных.
Список Х позволяет выбрать поле набора данных, значения которого будут последовательно откладываться по оси абсцисс. Список Y позволяет выбрать поле набора данных, значения которого будут отложены по оси ординат. Соответствие между значениями полей по двум осям определяется принадлежностью к одной записи набора данных. Выбор поля в списке Labels привязывает его значения в виде меток к оси абсцисс.
Здесь описан набор элементов управления для линейного типа серии. Для других типов элементы управления могут отличаться.
Теперь осталось только открыть набор данных и компонент TDBChart построит график.
Аналогичным образом на этот же компонент можно поместить и другие графики.
Таблица 18.8. Свойства и методы компонента TDBChart.
Объявление |
Описание |
Свойства |
|
Property AutoRefresh : Boolean; |
Разрешает или запрещает обновление данных в серии при открытии связанного набора данных |
Property Refreshlnterval : Longint; |
Задает временной интервал в секундах между обновлениями данных в сериях из связанных наборов данных |
Property ShowGlassCursor : Boolean; |
Разрешает показ курсора "песочные часы" при обновлениях данных |
Методы |
|
Procedure CheckDataSource ; |
Обновляет данные в сериях |
Function IsValidDataSource (AS eries: TChartSeries; Acomponent:Tcomponent):Boolean; virtual; |
Проверяет, связан ли набор данных AComponent с серией ASeries. В случае успеха проверки возвращает True |
Procedure RefreshData; |
Обновляет данные во всех сериях |
Procedure RefreshDataSet(AData Set: TdataSet; Aseries: TchartSeries) ; |
Считывает все записи в наборе данных ADataSet и переносит их в серию ASeries
|
Методы-обработчики событий |
|
Property OnProcessRecord : TprocessRecordEvent; |
Вызывается при переносе данных из отдельной записи набора данных в серию |
Поиск данных
В наборе данных реализованы два способа поиска записей по заданным значениям полей. Один способ основан на использовании индексов и является более быстрым, но поиск проводится только по индексированным полям. Второй способ использует специальные методы класса TBDEDataSet и позволяет проводить поиск по любому сочетанию полей, но он более медленный.
Поиск по индексам
Для организации индексного поиска к набору данных должен быть подключен инднкс (свойства IndexName или IndexFieldNames).
Метод FindKey проводит поиск записи по заданным в параметре значениям ключевых полей текущего индекса набора данных. В случае успеха курсор набора данных устанавливается на найденной записи, а метод возвращает значение True. В противном случае возвращается False.
Если индекс состоит из нескольких полей, значения для поиска записываются в виде множества, причем отсутствующие значения приравниваются к Null.
Рассмотрим простейший пример, в котором реализован поиск по вторичному индексу в таблице CUSTOLY.DB демонстрационной базы данных DBDEMOS. Индекс основан на полях Last_Name и FirstJName (рис. 18.8).
Рис. 18.8. Главная форма проекта DemoFind
В компоненте Tabiel, помимо стандартных настроек на таблицу, при помощи свойства indexName задан и вторичный индекс (его имя Names). Значения для поиска задаются в компонентах Editi и Edit 2.
Листинг 18.1 Секция Implementation главного Модуля Main проекта DemoFind
implementation
{$R *.DFM}
procedure TFormI.FormShow(Sender: TObject);
begin try Editi.Clear;
Edit2.Clear;
Tabiel.Open;
except on E: EDBEnqineError do ShowMessage('Ошибка при открытии таблицы');
end;
end;
procedure TFormI.FormClose(Sender: TObject; var Action: TCloseAction);
begin try finally Tabiel.Close;
end;
end;
procedure TFormI.FindBtnClick(Sender: TObject);
begin
if Tabiel.PindKey([Editi.Text, Edit2.Text]) then ShowMessage("Запись найдена') else ShowMessage('Запись не найдена');
end;
end.
Набор данных открывается в методе-обработчике FormShow при открытии формы и закрывается в методе-обработчике FormClose. При щелчке на
кнопке FindBtn в метод FindKey передаются значения для поиска из компонентов Editi И Edit2.
Поиск в диапазоне
Кроме этого, индексный поиск можно организовать группой методов, подобно созданию диапазонов. Метод setKey переводит набор данных в состояние dsSetKey, затем должно следовать присваивание ключевым полям значений для поиска. Сам поиск осуществляется методом GotoKey:
with Tablel do begin
SetKey;
Fields[0].Value := '428';
GotoKey;
end;
В случае успеха курсор набора данных устанавливается на найденной записи, а метод возвращает значение True. Вместо этого метода можно применять метод GotoNearest, который в случае неудачного поиска ищет запись, минимально отличающуюся от критерия поиска.
Изменение параметров поиска осуществляется методом EditKey.
Поиск по произвольным полям
Для поиска по произвольной выборке полей можно использовать методы
Locate И Lookup.
function Locate(const KeyFields: string; const KeyValues: Variant;
Options: TLocateOptions): Boolean; function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant;
В метод Locate необходимо передать список полей, по которым будет идти поиск (параметр KeyFields, имена полей разделяются точкой с запятой), их требуемые значения (параметр KeyValues, значения разделяются запятой) и настройки поиска (параметр options). В настройках можно задать параметр locaseinsensitive, который отключает проверку на регистр символов и параметр loPartialKey, который включает поиск с минимальными отличиями. В случае успеха поиска курсор набора данных устанавливается на найденной записи, а метод возвращает значение True.
Tablel.Locate('Last_Name;First_Name', VarArrayOf(['Editi.Text', 'Edit2.Text']), []);
В метод Lookup передается список полей для поиска (параметр KeyFields, имена полей разделяются точкой с запятой) и их требуемые значения (параметр Keyvalues, значения разделяются запятой). В случае успешного поиска функция возвращает массив значений типа вариант для полей, названия которых содержатся в параметре Result-Fields.
Tablel.Lookup('Last_Name;First_Name', VarArrayOf(['Editl.Text, 'Edit2.Text' ] ) , 'LastJSIame; First_Name' ) ;
Оба эти метода автоматически используют быстрый индексный поиск в случае, если в параметре KeyFieids задать поля индекса..
Фильтры
Наиболее эффективным способом отбора записей в набор данных (особенно из больших таблиц) является создание и выполнение соответствующего запроса SQL. Но что делать, если набор данных функционирует на базе компонента TTable? В этом случае на помощь приходит встроенный в набор данных механизм фильтрации данных.
Применение фильтра основано всего на двух основных свойствах и одном вспомогательном. Текст фильтра должен содержаться в свойстве Filter, a свойство Filtered включает и выключает фильтр. Параметры фильтра определяются свойством FilterOptions.
Компонент TQuery также может использовать фильтры. Эта возможность подчас позволяет легко и изящно решать довольно сложные проблемы, которые иначе требуют изменения текста запроса или создания нового компонента запроса.
При использовании фильтра его текст транслируется BDE в синтаксис SQL и передается для выполнения на сервер или через соответствующий драйвер в локальную СУБД.
Фильтры можно создавать двумя способами:
Фильтры можно разделить на статические и динамические. Статические фильтры создаются во время разработки приложения и могут использовать как свойство Filter, так и метод OnFiiterRecord.
Динамические фильтры можно создавать и редактировать во время выполнения приложения, для них используется только свойство Filter.
При создании текста фильтра для свойства Filter используются имена полей соответствующей таблицы БД, а для задания отношений применяются все операторы сравнения (>, >=, <, <=, =, <>) и логические операторы and, OR, NOT:
Fieldl>100 AND Field2=20
Сравнивать между собой два поля нельзя. Следующий фильтр вызовет ошибку при попытке использования:
ItemCount-Balance AND InputPrice>OutputPrice
При создании динамических фильтров можно изменять как выражение фильтра целиком, так и его части. Например, ограничивающее значение для поля можно задавать при помощи элементов управления формы, что позволяет пользователю приложения управлять фильтрацией набора данных:
procedure TFormI.EditlChange(Sender: TObject);
begin with Tablel do begin Filtered :- Falser; Filter := 'Fieldl>=' + (Sender as TEdit).Text;
Filtered := True;
end;
end;
В фильтрах можно производить отбор по частям строк для строковых полей, для этого используется символ звездочки (*):
ItemName-'A*'
Фильтр начинает работать только после того, как свойству Filtered присваивается истинное значение. Перед изменением текста динамического фильтра или для отключения фильтра свойству Filtered присваивается значение False.
Параметры фильтра определяются свойством FilterOptions:
property FilterOptions: TFilterOptions;
TFilterOption - (foCaseInsensitive, foNoPartialCompare);
TFilterOptions = set of TFilterOption;
Параметр foCaseInsensitive, будучи включенным, отключает сравнение строковых значений с учетом регистра символов.
Параметр foNoPartialCompare отключает отбор строковых значений по части строки.
Метод-обработчик onFilterRecord имеет следующее объявление:
type TFilterRecordEvent = procedure(DataSet: TDataSet; var Accept:
Boolean) of object; property OnFilterRecord: TFilterRecordEvent;
Если этот метод создан для набора данных, то он вызывается для каждой его записи. Программный код метода должен присваивать параметру Accept истинное или ложное значение. В результате запись передается в набор данных или отсекается:
procedure TFormI.TablelFilterRecord(DataSet: TDataSet;
var Accept: Boolean);
begin Accept := ArchOrdersArchDat.AsString >= DateEditI.Text;
end;
Важнейшее преимущество метода OnFilterRecord по сравнению со свойством Filter в том, что в этом методе-обработчике можно сравнивать поля и производить вычисления над их значениями.
Недостатком метода является недостаточная гибкость, хотя такой фильтр можно модифицировать путем присвоения методу процедурной переменной, содержащей ссылку на новый метод.
Быстрый переход к помеченным записям
Закладки, как инструмент работы с записями набора данных, позволяет осуществлять быстрое перемещение на нужную запись. Набор данных может содержать неограниченное число закладок, каждая из которых представляет собой указатель. Закладку можно создать только для текущей записи набора данных.
При работе с закладками используются три основные метода.
Кроме этого, можно использовать метод BookmarkValid, который проверяет, указывает ли закладка на реально существующую запись. Метод CompareBookmark, который позволяет сравнить между собой две закладки:
var Bookmarki, Bookmark2: TBookmark;
if Tablel.CompareBookmark(Bookmarki, Bookmark2) = 1 then ShowMessage ( 'Закладки одинаковы' ) ;
В наборе данных имеется свойство Bookmark, которое содержит название
текущей закладки.
Рис. 18.9. Главная форма проекта DemoBookmark
Рассмотрим небольшой пример, где право управлять закладками предоставлено пользователю (рис. 18.9). На форме, помимо других элементов управления (среди которых есть компонент TDBGrid), имеется две кнопки. Кнопка StartBookmark помечает текущую запись, кнопка StopBookmark переходит к закладке, а затем уничтожает ее.
Листинг 18.2 Пример использования закладок
var SaveRecPos: TBookmark;
procedure TFormI.FormShow(Sender: TObject);
begin
try Tablel.Open;
BookmarkControl.Brush.Color := clBtnFace;
except ShowMessage('Ошибка открытия набора данных');
end;
end;
procedure TFormI.FormClose(Sender: TObjeCt; var Action: TCloseAction) ;
begin
try
finally Tablel.Open;
end;
end;
procedure TForml.StartBookmarkClick(Sender: TObject);
begin
if Not Tablel.BookmarkValid(SaveRecPos)
then SaveRecPos := Tablel.GetBookmark;
BookmarkControl.Brush.Color := cILime end;
procedure TForml.StopBookmarkClick(Sender: TObject);
begin
with Tablel do
begin
if Not BookinarkValid( SaveRecPos) then Exit;
GotoBookmark(SaveRecPos);
FreeBookmark(SaveRecPos);
end;
BookmarkControl.Brush.Color := clBtnFace;
end;
Использование метода Bookmarkvalid позволяет корректно переопределять закладку, если она уже установлена, и избежать ошибок при произвольных нажатиях кнопок. Компонент BookmarkControl типа TShape сигнализирует о том, что закладка установлена или удалена.
Закладки также используются в компоненте TDBGrid. Он имеет свойство SelectedRows типа TBookmarkList, которое представляет собой список закладок, указывающих на одновременно выделенные записи.
Диапазоны
В наборе данных, помимо фильтров, имеется еще одно средство отбора записей. Группа методов позволяет на основе использования индексов отбирать в набор данных только те записи, значения индексированных полей которых (для текущего индекса) соответствуют диапазону заданных величин.
Диапазоны работают быстрее фильтров, но менее гибки и не так удобны в работе. При использовании диапазонов набор данных обязательно должен находиться в состоянии dsSetKey (см. ниже).
Для того чтобы включить диапазон, необходимо задать стартовое и конечное значение диапазона для ключевых полей, затем применить созданный диапазон к набору данных. Работающий диапазон можно модифицировать.
Все методы работы с диапазонами используют те поля, которые заданы в текущем индексе. Для таблиц Paradox и dBASE это свойство indexName. Для таблиц серверов SQL это свойство indexFieldNames.
Метод setRangeStart переводит набор данных в режим dsSetKey, следующее за этим присваивание ключевым полям означает задание начальной границы диапазона.
Метод setRangeEnd также переводит набор данных в режим dsSetKey, следующее за этим присваивание ключевым полям означает задание конечной границы диапазона.
После этого необходимо использовать метод ApplyRange, который применяет созданный диапазон к набору данных:
with Tablel do begin
SetRangeStart;
Fields[0].Value := '439';
SetRangeEnd;
Fields[1].Value := '522';
ApplyRange;
end;
Работающий диапазон можно модифицировать аналогичным образом: после вызова методов EditRangeStart и EditRangeEnd необходимо задать новые границы для ключевых полей и снова вызвать метод ApplyRange:
with Tablel do begin
EditRangeStart;
Fields [0] .Value := '500';
EditRangeEnd;
Fields[1].Value := '522';
ApplyRange; end;
Отмена диапазона осуществляется методом cancelRange.
Если индекс содержит несколько полей, то перед вызовом метода ApplyRange необходимо задать значения для всех ключевых полей.
Для одновременного задания верхней и нижней границы диапазона можно использовать метод SetRange.
with Tablel do begin
SetRange(['500'], ['522']);
ApplyRange;
end;
Тем, какая граница будет у диапазона — открытая или закрытая, управляет свойство KeyExclusive. Если оно имеет значение True, граничные значения в диапазон не включаются, в противном случае — включаются.
Резюме
Компоненты отображения данных играют важную роль при создании интерфейсов приложений баз данных. Разнообразие предлагаемых элементов управления позволяют решать любые задачи по организации взаимодействия пользователя с базой данных. Все они взаимодействуют с набором данных Через компонент TDataSource.
В этой главе также представлены разнообразные программные механизмы, обеспечивающие редактирование и управление данными в приложениях.
Материал данной главы основан на сведениях, излагаемых в главах 16 "Набор данных" и 17 "Поля".