Читайте также:
|
|
Отчет должен содержать:
1. Тексты обработчиков событий OnShow и OnClose главной формы приложения.
2. Тексты процедур расчета интегральных показателей.
3. Все экранные формы работающего приложения и тексты процедур обработки нажатия всех кнопок.
Замечание: приводимые в отчетах фрагменты программного кода должны содержать необходимые комментарии.
4. ЛАБОРАТОРНАЯ РАБОТА №4
Тема работы: фильтрация и поиск в наборах данных.
Длительность работы: 8 академических часов.
5.1. ФИЛЬТРАЦИЯ НАБОРОВ ДАННЫХ
Фильтрация - это отображение в НД только тех записей, которые удовлетворяют определенному условию (фильтру).
Для осуществления фильтрации в TDataSet используются свойства: Filter, FilterOptions, Filtered и событие OnFilterRecord.
В свойстве Filter указывается условие фильтрации в виде строки SQL-подобного синтаксиса. В этой строке могут использоваться только имена полей, литералы (явно заданные значения), операторы отношения (>, <, <=, =>,<>), а также логические операторы (OR, AND, NOT). Переменные, объявленные в программе, здесь использовать нельзя.
Например, для показа только тех проводок, в которых передающим было лицо с условным номером 1, а принимающим – с номером 3, фильтр следует задать следующим образом:
DM.ProvodkiT.Filter:= ’([Rashod]=1) AND ([Prihod]=3)’;
Свойство FilterOptions устанавливает режимы выполнения фильтрации для условия Filter (и только для него). Можно указать два режима:
foCaseInsensitive - игнорирование регистра букв;
foNoPartialCompare - поиск по точному соответствию. Если этот режим выключен (foNoPartialCompare = False), то в фильтре можно использовать символ ‘*’ для указания произвольного числа любых символов. Например, для выбора всех лиц, наименование которых начинается с «Ив», «ИВ», «ив», следует задать фильтр:
DM.LicoTb.Filter:=’[Name]=”ИВ*”’;
с включенной опцией foCaseInsensitive и выключенной foNoPartialCompare.
Гораздо большие возможности фильтрации представляет обработчик события OnFilterRecord. Его процедура имеет два параметра: имя фильтруемого НД и параметр Accept. В отфильтрованный НД включаются только те записи, для которых в теле процедуры Accept будет установлен в True. Приведенный выше пример можно переписать следующим образом:
procedure DM.ProvodkiT.FilterRecord(DataSet: TDataSet;
var Accept: Boolean);
begin
Accept:= (DataSet[‘Rashod’]=1) AND (DataSet[‘Prihod’]=3);
end;
Следует отметить, что обработчик OnFilterRecord представляет более гибкие возможности для фильтрации НД, чем свойство Filter. В частности, в нем можно использовать и программные переменные.
Свойство Filtered используется для включения/выключения фильтрации. Причем это касается фильтрации, заданной как в свойстве Filter, так и в обработчике OnFilterRecord.
Замечание1: фильтры в свойстве Filter и обработчике OnFilterRecord могут использоваться одновременно. Соответственно, в отфильтрованный НД будут включаться записи, удовлетворяющие обоим условиям фильтрации.
Замечание2: в условия фильтрации могут включаться любые поля, в том числе и те, по которым индексы не строились. Как следствие, фильтрация может потребовать полного перебора всех записей НД. Поэтому использовать в фильтрах неиндексированные поля для больших НД следует с осторожностью, чтобы не замедлить работу с БД. Для ускорения фильтрации можно использовать метод SetRange компонента TTable, который работает только с индексированными полями.
Приведем пример использования фильтрации. Необходимо на форме с таблицей лиц (рис. 27) показывать лица только определенного типа (тип выбирается с помощью RadioGroup), если отмечен соответствующий CheckBox.
// Процедура включения/выключения фильтрации
procedure TMainForm.TipCheckBoxClick(Sender: TObject);
begin
DM.LicaT.Filtered:= TipCheckBox.Checked;
end;
// Процедура задания фильтра
procedure TMainForm.TipRadioGroupClick(Sender: TObject);
begin
DM.LicaT.Filtered:= false; // Выключаем фильтрацию
case TipRadioGroup.ItemIndex of // Задаем фильтр
0: DM.LicaT.Filter:= '[Tip]=2';
1: DM.LicaT.Filter:= '[Tip]=1';
2: DM.LicaT.Filter:= '[Tip]=3';
else DM.LicaT.Filter:= '';
end;
// Восстанавливаем состояние фильтрации
DM.LicaT.Filtered:= TipCheckBox.Checked;
end;
Рис. 27. Фильтрация таблицы лиц
Задание.
1. Подумайте, какие фильтры были бы полезны для пользователей Вашего приложения. Реализуйте их. Тексты процедур и соответствующие экранные формы включите в отчет.
5.2. ПОИСК В НАБОРАХ ДАННЫХ
Как для компонента TDataSet в целом, так и для компонента TTable в частности реализовано несколько методов поиска, позволяющих найти нужную запись в наборе данных по значениям ее полей. Рассмотрим некоторые из этих методов.
Метод Locate – общий для всех потомков TDataSet. Он ищет первую запись, имеющую искомые значения полей. Если такая запись найдена, то делает ее текущей и возвращает True, иначе False. Метод определяется следующим образом:
function Locate(const KeyFields: string;
const KeyValues: Variant;
Options: TLocateOptions): Boolean;
Параметр KeyFields содержит список имен полей, по которым производится поиск. Имена в списке разделяются точкой с запятой.
Параметр KeyValues - вариантный массив, который содержит искомые значения. Первое значение для первого поля из списка KeyFields, второе – для второго и т.д.
Параметр Options указывает условия поиска:
loCaseInsensitive - игнорирование регистра букв;
loPatrtialKey - поиск по частичному соответствию, то есть могут быть заданы только начальные символы значения (здесь символ ‘*’ не используется).
Для примера реализуем с помощью рассмотренного метода поиска процедуру выполнения проводки. В качестве параметров этой процедуре передаются условные номера лица расхода, лица прихода и передаваемого предмета, а также его количество и дата проводки. Предполагается, что эти параметры были предварительно проверены на допустимость проводки, т.е. на соответствие всем бизнес-правилам.
Необходимо: у передающего лица (если это подотчетное лицо) уменьшить наличие передаваемого предмета. Если в результате выполнения проводки у передающего лица не останется указанных предметов, то соответствующая строка из таблицы наличия должна быть удалена. У принимающего лица (если это подотчетное лицо) надо увеличить наличие передаваемого предмета. Если у него не было таких предметов, то следует добавить в таблицу наличия соответствующую строку. Наконец, информация о выполненной проводке должна быть записана в таблицу проводок.
procedure DoProvod(rashod, prihod, predmet: integer; kolvo: double; data: TDateTime);
begin
// Ищем лицо расхода в таблице лиц
if DM.LicaT.Locate('NLic', rashod, []) then
if DM.LicaTTip.AsInteger = 2 then // Если это п/о лицо
// Ищем у него наличие передаваемого предмета
if DM.NalichieT.Locate('Lico;Predmet', VarArrayOf([rashod, predmet]), []) then
// Если у него предметов больше, чем надо передать
if DM.NalichieTKolvo.AsFloat > kolvo then
begin // Уменьшаем наличие
DM.NalichieT.Edit;
DM.NalichieTKolvo.AsFloat:= DM.NalichieTKolvo.AsFloat - kolvo;
DM.NalichieT.Post;
end
else // Иначе удаляем строку наличия
DM.NalichieT.Delete
else
begin
ShowMessage('Ошибка при поиске наличия у лица расхода');
exit;
end
else
else
begin
ShowMessage('Ошибка при поиске лица расхода');
exit;
end;
// Ищем лицо прихода в таблице лиц
if DM.LicaT.Locate('NLic', prihod, []) then
if DM.LicaTTip.AsInteger = 2 then // Если это п/о лицо
// Ищем у него наличие передаваемого предмета
if DM.NalichieT.Locate('Lico;Predmet', VarArrayOf([prihod, predmet]), []) then
begin // Если предмет есть в наличии, то увеличиваем его кол-во
DM.NalichieT.Edit;
DM.NalichieTKolvo.AsFloat:= DM.NalichieTKolvo.AsFloat + kolvo;
DM.NalichieT.Post;
end
else
begin // Иначе добавляем строку в наличие
DM.NalichieT.Insert;
DM.NalichieTLico.AsInteger:= prihod;
DM.NalichieTPredmet.AsInteger:= predmet;
DM.NalichieTKolvo.AsFloat:= kolvo;
DM.NalichieT.Post;
end
else
else
begin
ShowMessage('Ошибка при поиске лица прихода');
exit;
end;
// Добавляем проводку в таблицу проводок
DM.ProvodkiT.Insert;
DM.ProvodkiTRashod.AsInteger:= rashod;
DM.ProvodkiTPrihod.AsInteger:= prihod;
DM.ProvodkiTPredmet.AsInteger:= predmet;
DM.ProvodkiTKolvo.AsFloat:= kolvo;
DM.ProvodkiTData.AsDateTime:= data;
DM.ProvodkiT.Post;
end;
Замечание: поиск методом Locate возможен по любым полям, в том числе и по неиндексированным. Если индексы есть, то они используются. Если есть несколько индексов по полям поиска, то предсказать какой из них будет использован нельзя. Поэтому если искомое значение содержится в нескольких записях, то предсказать какая из записей будет найдена первой нельзя. При отсутствии индексов метод работает медленно, поскольку выполняет последовательный перебор записей.
Помимо методов для TDataSet в TTable могут использоваться методы FindKey и FindNearest. Поиск этими методами возможен только по полям текущего индекса. Допустим поиск и по части полей, но эти поля должны быть ведущими и следовать подряд.
Метод FindKey определяется следующим образом:
function FindKey(const KeyValues: array of const): boolean;
Он ищет первую запись, у которой значение индексных полей точно совпадают с искомыми значениями в KeyValues. Если запись найдена, то курсор перемещается на нее и метод возвращает True. В противном случае – False и курсор не перемещается.
Метод FindNearest рассчитан на приближенный поиск. В начале он делает попытку найти запись, точно соответствующую искомым значениям. Если запись найдена, то происходит перемещение курсора в зависимости от свойства НД KeyExclusive. Если оно – False (по умолчанию), то курсор переходит на найденную запись. Если же True, то на запись, следующую за найденной.
Если точно соответствующая запись не найдена, курсор перемещается на запись с ближайшим большим значением индексных полей. Причем сначала происходит наращивание значения самого внутреннего поля в индексе.
С помощью метода FindNearest легко реализуется так называемый инкрементальный локатор – это механизм поиска записей в НД, при котором поиск производится по мере ввода искомого значения. Для ввода значения может быть использован, например, компонент TEdit.
Пусть НД LicaT отсортирован по индексу, построенному по полю Name и содержит записи со следующими лицами:
Афанасьев
...
Лосев
Малов
Молотов
Мосин
...
Тогда после ввода в TEdit буквы ‘М’ текущей должна стать запись ‘Малов’; после ввода ‘Мо’ – ‘Молотов’; после ‘Мос’ - ‘Мосин’ и т.д.
Такой алгоритм можно реализовать, например, с помощью следующего обработчика события OnChange компонента TEdit:
procedure TForm1.Edit1Change(Sender: TObject);
begin
DM.LicaT.FindNearest([Edit1.Text]);
end;
При реализации инкрементального локатора можно обойтись и без TEdit. Например, если DBGrid не используется для непосредственной модификации НД, то локатор можно реализовать в обработчике события OnKeyPress соответствующего компонента TDBGrid. Тогда (если фокус ввода принадлежит DBGrid) при наборе символов будет происходить перемещение к требуемой строке.
Для наглядности вводимые символы можно отображать в какой-либо метке. А для простоты перехода к новому поиску – сбрасывать введенное значение с некоторой задержкой. Например, сбрасывать его по истечении 2 секунд после ввода последнего символа.
Задание.
2. Подумайте, какие операции будут выполнять пользователи с помощью Вашего приложения, какие обработки хранимой информации им понадобятся, какие преобразования и т.д., т.е. каково будет функциональное наполнение Вашего приложения. Как обеспечить максимальное удобство работы с Вашим приложением. В частности, предусмотрите инкрементальные локаторы в тех таблицах, где они будут полезны пользователям. Обсудите свои идеи с преподавателем. Реализуйте полномасштабное приложение с использованием полученных навыков.
Дата добавления: 2015-07-07; просмотров: 118 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Требования к отчету по лабораторной работе №2. | | | Требования к отчету по лабораторной работе №4. |