Некоторые компоненты визуализации и управления данными

 

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

Щелкните правее этого свойства в Инспекторе Объектов. На экране появится пустое окно Редактора Столбцов (рис. 2.4.). Вы можете добавлять столбцы по од­ному, щелкая на быстрой кнопке Add (первая слева) и указывая для них в Инспек­торе Объектов соответствующие поля в свойстве FieldName. To же самое можно де­лать, щелкая правой кнопкой мыши и выбирая в контекстном меню раздел Add. A можно поступить иначе: выбрать из контекстного меню раздел Add All Fields или щелкнуть на соответствующей быстрой кнопке (вторая справа). В окне Редактора Столбцов появится список столбцов всех полей, которые добавлены вами в Редак­торе Полей компонента Table. Затем кнопкой Delete (вторая слева) вы можете уда­лить столбцы, ненужные в таблице.

 

Рис. 2.4. Главное окно редактора столбцов

 

Выделите в Редакторе Полей столбец, связанный с полем Edenica, и посмотрите его свойства в Инспекторе Объектов. Среди многих достаточно очевидных свойств столбца, Вы увидите свойство ButtonStyle. Оно определяет стиль ввода данных в поле текущей записи. Свойство ButtonStyle может принимать значения, указанные в табл. 1.

Таблица 1

Значения свойства ButtonStyle

cbsAuto Появление при редактировании кнопки, связанной с выпадающим списком допустимых значений
cbsEllips Появление при редактировании кнопки с многоточием «...» при щелчке на которой наступает событие OnEditButtonClick компонента DBGrid (см. рис. 2.5)
cbsNone Обычное редактирование без каких-либо кнопок

 

Если установить значение cbsAuto (оно принято по умолчанию), то можно дополнительно установить свойство столбца PickList, которое представляет список допустимых значений поля. В нашем примере для столбца Edenica можно занести в список PickList значения «шт.», «т.» и «кг.». Тогда при попытке пользователя редактировать данное поле в соответствующей ячейке таблицы появится кнопка, связанная с выпадающим списком, содержащим допустимые значения (рис. 2.6).

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

Если значение свойства ButtonStyle равно cbsNone, то редактирование поля производится без каких-либо подсказок в виде кнопок.

Компонент DBGrid — удобный, но далеко не единственный и не всегда лучший компонент визуализации. Форма представления данных в нем не всегда удобная: слишком регулярная, без разделителей, не акцентирующая внимание пользователя на каких-то группах полей. Имеется много других компонентов визуализации и управления данными, расположенными на странице Data Control библиотеки компонентов, которые нередко предпочтительнее DBGrid.

 

Рис. 2.5. Ячейка поля Edinica при ButtonStyle= cbsEllips

 

Отметим некоторые из этих компонентов.

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

 

Рис. 2.6. Ячейка поля Edinica при ButtonStyle= cbsAuto

 

DBEdit — связанный с данными аналог обычного окна редактирования Edit. Он позволяет отображать и редактировать данные полей различных типов: строка, число, булевская величина. Впрочем, если задать в компоненте Readonly=true, он, как и DBText, будет служить элементом отображения, но несколько более изящным, чем DBText.

DBMemo — связанный с данными аналог обычного многострочного окна редактирования Memo. Он позволяет отображать и редактировать данные поля типа Memo, а также данные любых типов, указанных выше для предыдущих компонентов.

DBRichEdit— связанный с данными аналог обычного многострочного окна редактирования текста в обогащенном формате RTF. Область применения та же, что и для компонента DBMemo.

DBlmage — связанный с данными аналог обычного компонента Image. Компонент позволяет отображать графические поля.

DBCheckBox — связанный с данными аналог обычного индикатора CheckBox. Он позволяет отображать и редактировать данные поля булевского типа. Если при вводе данных поле имеет значение true, то индикатор включается. И наоборот, при редактировании поля присваиваемое ему значение определяется состоянием индикатора. Кстати, это еще один способ обеспечить пользователю безошибочный ввод значений в булевское поле, помимо рассмотренного выше задания списка воз­можных значений в DBGrid.

DBRadioGroup — связанный с данными аналог группы радиокнопок RadioGroup. Компонент позволяет отображать и редактировать поля с ограниченным множеством возможных значений. Свойство Items, как и в обычной группе радиокнопок, определяет число кнопок и надписи около них. Но есть еще свойство Values, которое определяет значения полей, соответствующие кнопкам. Таким образом, надписи у кнопок и значения полей в общем случае могут не совпадать друг с другом. Если свойство Values не задано, то в качестве значений полей берутся строки из свойст­ва Items, т.е. надписи около кнопок. Компонент DBRadioGroup предоставляет еще одну возможность ввода пользователем данных путем выбора, а не написанием полного значения поля.

Есть еще несколько компонентов визуализации и управления данными, кото­рые мы рассмотрим несколько позднее. Все перечисленные компоненты имеют два основных свойства: DataSource — источник данных (компонент типа TDataSourсе) и DataField — поле, с которым связан компонент.

Характерной особенностью всех этих компонентов, отличающей их от несвя­занных с данными аналогичных компонентов, является отсутствие в окне Инспек­тора Объектов их основных свойств, отображающих содержание: Caption в DBText, Text в DBEdit, Picture в DBImage и т.п. Все эти свойства имеются в ком­понентах, но они доступны только во время выполнения. Так что программно их можно читать, редактировать, устанавливать, но во время проектирования задать их значения невозможно. Это естественно, так как эти свойства — это значения со­ответствующих полей таблицы базы данных.

 

Компонент Session

 

Компоненты Sessionосуществляют общее управление связыванием приложения с базами данных. Обычно пользователю не приходится заботиться о компонен­те Session, поскольку Delphi автоматически генерирует объект Sessionв каждом приложении, работающем с базами данных. На этот объект можно ссылаться через глобальную переменную Session.

Компонент Sessionимеет много полезных методов и позволяет легко работать с BDE. Приведем простой пример использования некоторых методов Session.Да­вайте построим приложение, позволяющее просматривать любую заданную поль­зователем таблицу в любой заданной им доступной базе данных. Это приложение (рис. 2.7) содержит два выпадающих списка типа TComboBox.Первый из них предназначен для выбора пользователем базы данных, а второй — для выбора таблицы. Кнопка Просмотр предназначена для просмотра выбранной таблицы в компоненте типа TDBGrid,связанном цепочкой ссылок с компонентами DataSourcel и Table 1.

Рис. 2.7. Приложение, позволяющее пользователю выбрать любую доступную базу данных и любую таблицу в ней

 

Чтобы такое приложение функционировало, надо при создании формы загрузить список cbDatabaseдоступными BDE псевдонимами. Это делается следующим оператором, помещенным в обработчик события OnCreateформы:

 

Session.GetAliasNames(ComboBox1.Items);

 

Этот оператор использует метод GetAliasNamesобъекта Session,который передает в свой параметр типа TStrings(в данном примере это список cbAlias.Items)перечень псевдонимов баз данных, зарегистрированных в BDE.

При выборе пользователем базы данных в списке cbAlias надо загрузить список cbTable перечнем таблиц выбранной базы данных. Это делается включением в обработчик события OnChange компонента cbAlias операторов:

 

Sesion.GetTableNames(ComboBox1.Text,'',true,false,ComboBox2. Items);

ComboBox2.ItemIndex:=0;

 

Первый из этих операторов использует метод GetTableNames для загрузки в свой последний параметр типа TStrings (в данном примере это список ComboBox2.Items) перечня таблиц базы данных, заданной своим первым параметром (в данном это ComboBox1.Text). Второй параметр метода позволяет задать шаблон, отбирающий имена таблиц. Например, шаблон «р*» отберет имена таблиц, начинающиеся с символа «р». Пустой шаблон, использованный в примере, означает выбор всех таблиц. Третий параметр, установленный в true, означает, что в имена таблиц будут включаться расширение файла (это необходимо для таблиц Paradox и dBase). Четвертый параметр задается равным false для баз данных Paradox и dBase, а для баз, основанных на SQL, этот параметр устанавливается в true, чтобы возвращать таблицы данных и системные таблицы, определяющие структуру данных. Теперь остается ввести в приложение обработчик нажатия кнопки «Просмотр». Этот обработчик может иметь вид:

 

If ComboBox2.Text='' then

begin

ShowMessage('Не задана таблица');

end;

Table1.Active:=false;

Table1.DatabaseName:=ComboBox1.Text;

Table1.TableName:=ComboBox2.Text;

Table1.Active:=true;

end;

 

Этот обработчик просто задает свойства DatabaseName и TableName и компонента Table1 равными выбранным пользователем значениям, и переводит Таble1 в активное состояние.

Откомпилируйте приложение и посмотрите его в работе.

Выше показано использование компонента Session, создаваемого неявно по умолчанию. Вводить явным образом компоненты Session приходится только в многозадачных приложениях, в которых предусмотрено несколько параллельных процессов со своими потоками обмена информацией с базой данных. В таких многопоточных приложениях обычно вводится явным образом по одному компоненту Session на каждый поток, чтобы исключить влияние потоков друг на друга. При явном вводе компонента Session в приложение следует установить свойство SessionName — имя сеанса сетевого соединения, задав в нем произвольный идентификатор, например, s1. После этого в выпадающих списках свойств SessionName компонентов типа TDatabase, ТТаblе, TQuery и т.п. появится введенное вами имя. Выбор соответствующего имени сеанса сетевого соединия этих списков свяжет эти компоненты с соответствующим компонентом Session.

Если в приложении имеется несколько компонентов Session, глобальная переменная Session по-прежнему одна. Она имеет тип TSessionsList и содержит данные о каждом компоненте Session.

 

Компонент Batch Move

 

Компонент BatchMove предназначен для групповых операций переноса данных из одного набора в другой. Основные свойства компонента: Source – источник данных и Destination – приемник данных типа TTable.Свойство Mode определяет режим переноса данных. представлены в таблице 2.

 

Таблица 2

Значения свойства Mode компонента BatchMove

batAppend Записи из источника данных добавляются в приемник, не изменяя существующих там записей. Таблица — приемник должна существовать до начала переноса данных.

 

 

Продолжение табл. 2

batUpdate Записи в таблице — приемнике с ключевыми полями, соот­ветствующими полям в таблице — источнике, изменяются на записи из источника. Новые записи в приемник не до­бавляются. Таблица — приемник должна существовать до начала переноса данных и должна иметь индекс.
batAppendUpdate Записи в таблице — приемнике с ключевыми полями, соот­ветствующими полям в таблице — источнике, изменяются на записи из источника. Записи из таблицы источника, ко­торые не имеют соответствия в приемнике, добавляются туда. Таблица — приемник должна существовать до начала переноса данных и должна иметь индекс.
batDelete Записи в таблице — приемнике, которым находится соответствие в источнике, удаляются из приемника. Таблица — приемник должна существовать до начала переноса данных и должна иметь индекс
batCopy Таблица — приемник создается и заполняется записями источника. Если таблица — приемник уже существовала, то ее содержимое заменяется на содержимое источника

 

Основной метод компонента — Execute выполняет операцию переноса дан­ных. Свойство MovedCount указывает число записей, успешно перенесенных в таблицу-приемник.

При переносе записей из одной таблицы в другую могут возникать проблемы, связанные с несоответствием типов полей в таблице-источнике и таблице-прием­нике. В этих случаях свойство AbortOnProblem указывает, должна ли немедленно прекращаться операция, вызвавшая несоответствие типов полей в таблице-источ­нике и таблице-приемнике. При задании AbortOnProblem = false желательно од­новременно задать свойство ProblemTableName. Это свойство указывает имя таб­лицы Paradox, в которую будут помещаться записи, в которых обнаружено несоот­ветствие типов полей и которые поэтому не помещены в приемник. Свойство ProblemCount определяет число записей, в которых возникли подобные пробле­мы. При задании AbortOnProblem = false записи с полями несоответствующих ти­пов нередко все-таки могут помещаться в таблицу-приемник. Дело в том, что ком­понент BatchMove пытается в этом случае преобразовать тип поля таблицы-источ­ника в тип поля таблицы-приемника. Если такое преобразование возможно, то никаких проблем при переносе записей не возникает.

В некоторых случаях перенос отдельных записей может оказаться невозможен из-за того, что они нарушают целостность данных в таблице-приемнике, например дублируют значения ключевого поля, которые должны быть уникальным, в этих случаях свойство AbortOnKeyViol указывает, должна ли немедленно прекращаться операция, вызвавшая нарушение целостности данных в таблице-приемнике. При задании AbortOnKeyViol = false желательно одновременно задать свойство KeyViolTableName. Это свойство указывает имя таблицы Paradox, в которую будут помещаться записи, которые не перенесены в приемник из-за нарушения целостности данных. Свойство KeyViolCount определяет число таких записей.

Поскольку при переносе данных могут возникать указанные выше и иные неприятности, в компоненте TBatchMove предусмотрен механизм, позволяющий произвести «откат» и сохранить прежние данные таблицы-приемника. Этому служит свойство ChangedTableName, в котором вы можете указать имя таблицы Paradox, создаваемой для сохранения копий всех изменяемых записей таблицы-приемника. Свойство ChangedCount содержит число записей, измененных или добавленных в таблице-приемнике (при Mode = batUpdate или batAppendUpdate), или удаленных из нее (при Mode = batDelete). Копии этих записей хранятся в таблице ChangedTableName.

Свойство Mappings типа TStrings позволяет задать таблицу соответствия источника и приемника. По умолчанию поля таблиц переносятся в поля приемника с теми же именами и в той же последовательности, как в источнике. Если это вас устраивает, то свойство Mappings задавать не надо. Но если вы зададите свойство Mappings, то можете изменить определенный по умолчанию способ переноса данных. Во-первых, вы можете задать в этом свойстве только часть полей, значения которых надо переносить. Имена полей записываются по одному в строчке. Значения полей, не указанные в Mappings, переноситься не будут. Более того, вы можете указать, в какое поле приемника надо переносить значение поля источника. Например, если вы задаете в Mappings строку:

 

Pokupatel,

 

то значение поля Pokupatel из источника будет переноситься в поле Dep приемника. Но если вы зададите строку:

 

Pokupatel= NewPokupatel,

 

то значение поля Pokupatel из источника будет переноситься в поле NewPokupatel приемник! Как видим, компонент BatchMove является очень удобным средством копирования, объединения, упорядочивания таблиц. Постройте тестовый пример, на котором вы сможете наглядно посмотреть различные режимы работы BatchMove. Пусть в этом примере можно будет создать копию таблицы Example, a затем оперировать с этой копией как с приемником. Копия будет иметь имя Example2.

Перенесите на форму по два экземпляра компонентов Table, DataSource и DBGrid. Одну цепочку этих компонентов (Table1, DataSource1 и DBGrid1) свяжите с источником — таблицей Example. Эта цепочка соответствует таблице-источнику Example, а в компоненте DBGrid1 можно будет просматривать ее и изменять содержа в ней информацию. Вторую цепочку (Table2, DataSource2 и DBGrid2) свяжите друг с другом, но не связывайте компонент Таblе2 ни с какой базой данных. Этот компонент будет приемником, в который будут переноситься данные из первой таблицы.

Добавьте на форму компонент BatchMove. В его свойстве Source задайте Table1, а в свойстве Destination — Таblе2. Свойство Mode можно установить любым, например, batCopy. Все равно режим переноса данных у нас будет задаваться программно. Добавьте на форму метку Labe1 для отображения числа скопированных записей. И добавьте ряд кнопок Button, соответствующих различным режимам переноса данных. Например, кнопку с надписью «Копировать» для режима batCopy, кнопку с надписью «Добавить» для режима batAppend и т.д. Добавьте также кнопку с надписью «Удалить таблицу», которая позволит удалять созданную таблицу Example2.

Введите в раздел private описания класса процедуру Exec, которая будет выполнять перенос данных из источника в приемник в заданном режиме. Реализация этой процедуры может иметь вид:

 

Procedure TForm1.Exec;

begin

Table2.Active:=false;

Table2.DatabaseName:=Table1.DatabaseName;

Table2.TableName:='Example2.db';

If (BatchMove1.Mode=batCopy) or (Table2.Exists) then

begin

BatchMove1.Execute;

Table2.Active:=true;

Label1.Caption:='Обработано'+

IntToStr(BatchMove1.MovedCount)+' записей';

end

else ShowMessage('Для выполнения этой операции'+

#13+ 'таблица должна существовать');

end;

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

Обработчики щелчков на кнопках, задающих режим, сводятся к заданию режима переноса данных и вызову процедуры Exec. Например, обработчик щелчка кнопки Копировать имеет вид: .

BatchMove1.Mode:=batCopy;

Exec;

остальные обработчики строятся аналогично. Только изменяется значение, присваиваемое свойству BatchMovel.Mode.

Обработчик щелчка на кнопке «Удалить таблицу» имеет вид:

 

If Table2.Exists then

begin

Table2.Active:=false;

Table2.DeleteTable;

end;

 

Если таблица-приемник существует, то она удаляется методом DeleteTable.

 


Обновление (Refresh)

 

Как Вы уже знаете, любая таблица, которую Вы открываете всегда “подвержена изменению”. Короче говоря, Вы должны расценить таблицу скорее как меняющуюся, чем как статическую сущность. Даже если Вы - единственное лицо, использующее данную TTable, и даже если Вы не работаете в сети, всегда существует возможность того, что программа с которой Вы работаете, может иметь два различных пути изменения данных в таблице. В результате Вы должны всегда знать, необходимо ли Вам обновить вид таблицы на экране.

Функция Refresh связана с функцией Open в том смысле, что она считывает данные или некоторую часть данных, связанных с данной таблицей. Например, когда Вы открываете таблицу, Delphi считывает данные непосредственно из файла БД. Аналогично, когда Вы регенерируете таблицу, Delphi считывает данные напрямую из таблицы. Поэтому Вы можете использовать эту функцию, чтобы перепрочитать таблицу, если Вы думаете что она могла измениться. Быстрее и эффективнее вызывать Refresh, чем вызывать Close и затем Open.

Имейте ввиду, однако, что обновление TTable может иногда привести к неожиданным результатам. Например, если пользователь рассматривает запись, которая уже была удалена, то она исчезнет с экрана в тот момент, когда будет вызван Refresh. Аналогично, если некий другой пользователь редактировал данные, то вызов Refresh приведет к динамическому изменению данных. Конечно маловероятно, что один пользователь будет изменять или удалять запись в то время, как другой просматривает ее, но это возможно.

 

Закладки (Bookmarks)

 

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

 

function GetBookmark: TBookmark;

(устанавливает закладку в таблице)

 

procedure GotoBookmark(Bookmark: TBookmark);

(переходит на закладку)

 

procedure FreeBookmark(Bookmark: TBookmark);

(освобождает память)

 

Как Вы можете видеть, вызов GetBookmark возвращает переменную типа TBookmark. TBookmark содержит достаточное количество информации, чтобы Delphi мог найти местоположение, к которому относится этот TBookmark. Поэтому Вы можете просто передавать этот TBookmark функции GotoBookmark и будете немедленно возвращены к местоположению, связанному с этой закладкой.

Обратите внимание, что вызов GetBookmark распределяет память для TBookmark, так что Вы должны вызывать FreeBookmark до окончания вашей программы и перед каждой попыткой повторного использования Tbookmark (в GetBookMark).

 

ЛАБОРАТОРНОЕ ЗАДАНИЕ

И МЕТОДИЧЕСКИЕ УКАЗАНИЯ

ПО ЕГО ВЫПОЛНЕНИЮ

 

Лабораторное задание

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



php"; ?>