Рис. 25. Модуль данных.
В Delphi 6, 7 для задания уникальных значений ключу num_xxx необходимо настроить свойство GeneratorField компонента IBDataSet.
2.3 Создание главной формы
Главная форма будет содержать меню (рис. 26) с пунктами, соответствующими выводу форм просмотра/корректировки таблиц и форм вывода отчетов (выходных документов). TMenu размещается со страницы компонент Standard. Формирование меню происходит при двойном щелчке мышью по помещенной на форму компоненте.


Рис. 26. Вид главной формы с раскрытыми меню на этапе проектирования.
Назовем форму FMain (свойство Name). Для того чтобы главная форма имела доступ к компонентам, расположенным в модуле данных, следует при создании этой формы выполнить пункт меню File – Use Unit и выбрать модуль, соответствующий модулю данных (Unit2). После этого все компоненты модуля данных будут доступны в главном модуле. Аналогичное действие следует выполнять для всех созданных форм просмотра и корректировки записей, а также для форм-отчетов.
В событии OnShow главной формы следует выполнить открытие БД с помощью строки:
Имя_модуля_данных. имя_компоненты_TIBDatabase. Open:
DM. IBDBSchool. Open; //Открываем БД
DM. IBTransaction1.Active:=true;
В событии OnClose следует выполнить закрытие БД:
DM. IBDBSchool. Close; //Закрываем БД
Для активизации формы, соответствующей выбранному пункту меню, следует выполнить вызов метода ShowModal этой формы: имя_формы. ShowModal. Например:
FClass. ShowModal; //Форма FСlass будет создана далее
2.4 Создание форм для просмотра/корректировки таблиц
Формы просмотра будут содержать экземпляр компоненты TDBGrid со страницы Data Controls. TDBGrid используется для показа содержимого набора данных в табличной форме, когда строки соответствуют записям НД, а столбцы – полям записи. Если полей слишком много, можно использовать компонент TDBCtrlGrid, который применяется для показа содержимого НД в виде формы.
Свойство TDataSource компоненты TDBGrid выбирается равным одному из экземпляров TDataSource.
Для указания столбцов таблицы используется редактор столбцов. Для его вызова необходимо при нахождении курсора мыши в области таблицы DBGrid нажать правую кнопку мыши и из контекстного меню выбрать пункт ColumnsEditor (рис. 27) и в появившемся окне добавить все поля НД:



Рис. 27. Доступные столбцы таблицы
Порядок следования столбцов в TDBGrid определяется порядком следования определений столбцов в редакторе столбцов (где можно менять их порядок).
Свойства отдельного столбца устанавливаются в окне Object Inspector. Они определяют особенности отображения столбца в TDBGrid.
Установку заголовка выделенного столбца можно сделать, выбрав в групповом свойстве столбца Title свойство Caption (рис. 28).
Здесь же можно поменять шрифт и цвет подписи (Font), установить выравнивание (Alignment), видимость поля (Visible).
Поля, являющиеся ключевыми (например, Num_class), следует сделать недоступным, для чего необходимо установить свойство Visible равным False.





Рис. 28. Свойства столбца
Для полей, имеющих фиксированное множество значений, которое остается неизменным на протяжении эксплуатации приложения, таких как пол, можно сформировать список возможных значений столбца. Для этого данное поле выбирается в редакторе столбцов и заполняется свойство PickList компоненты TDBGrid; каждое значение на новой строке. В свойство ButtonStyle необходимо установить значение cbsAuto. При прогоне программы, когда пользователь начнет редактирование значения в этом поле, в нем автоматически будет помещаться диалоговый элемент ComboBox.
Также на форме разместим кнопку Закрыть и на событие нажатия данной кнопки напишем код:
procedure TFClass. Button1Click(Sender: TObject);
begin
Close; //Закрываем форму
end;
После настройки форма классов примет вид (рис. 29):

Рис. 29. Форма «Классы»
Сделаем созданную форму диалоговой, для чего поменяем ее свойство BorderStyle на bsDialog (тогда пользователь не сможет изменять ее размер). В событии OnShow следует выполнить открытие таблицы БД:
DM. IBDSClass. Open;//Открываем набор данных
В событии OnClose формы следует закрыть таблицу:
DM. IBDSClass. Close;//Закрываем набор данных
Заметьте, что поле "Количество учеников" недоступно для изменения (ReadOnly = True). Оно меняется при изменении количества записей в таблице учеников (Pupil). Вынесем это поле на форму. Для этого сделаем его невидимым в TDBGrid, а на форму поместим экземпляр компоненты TDBText со страницы палитры компонент Data Controls. Ее свойство DataSourse (источник данных) установим равным DM. DS_Class, а DataField (поле данных) свяжем с полем KOL_PUPIL. Теперь данный компонент будет отображать значение поля KOL_PUPIL текущей записи. Так как значение этого поля изменяется с изменением таблицы Pupil, перед открытием формы следует переоткрыть компоненту IBDSClass. В связи с этим перепишем обработчик события OnShow данной формы следующим образом:
procedure TFClass. FormShow(Sender: TObject);
begin
DM. IBDSClass. Close;//закрываем на случай изменения кол-ва учеников
DM. IBDSClass. Prepare;//подготовка компоненты к открытию
DM. IBDSClass. Open;
end;
Аналогичным образом создаются все формы для ввода и корректировки данных таблиц БД.
Вид формы предметов учителей изображен на рис. 30 (вводится только величина нагрузки, поля Учитель и Предмет выбираются из созданных ранее lookup-полей):

Рис. 30. Форма «Предметы учителей»
Текущая строка (ячейка) выделяется синим пунктирным прямоугольником. Для вставки новой записи необходимо нажать на клавиатуре клавишу Insert или попытаться перейти с последней записи в НД вниз на одну строку. Для изменения записи достаточно ввести новое значение в какое-либо поле. Для удаления записи необходимо нажать комбинацию клавиш Ctrl+Delete.
2.5 Использование дополнительных возможностей
Для навигации по таблице можно использовать также компоненту DBNavigator со страницы Data Controls (рис. 31), связав ее с необходимой компонентой TDataSource (свойство DataSource).



Рис. 31. Использование компоненты DBNavigator.
Покажем на примере формы учеников использование компоненты TDBCtrlGrid для отображения данных. Для работы с компонентом необходимо поместить его на форму, связать с компонентой TDataSource, связанной с НД, и затем разместить на нем необходимые компоненты для работы с полями БД - TDBEdit, TDBComboBox и т. п. Разметим в верхней ячейке один экземпляр компоненты TDBComboBox, свойство DataField которого установим равным CL (из выпадающего списка), два экземпляра компоненты TDBEdit, связав первый с полем FIO_PUPIL, второе - с BALL. Также поместим метки Label - подписи к полям (рис. 32 справа).
Во время выполнения приложения расположение компонентов в верхней строке (ячейке) TBDCtrlGrid и их состав будет реплицирован на все оставшиеся строки (ячейки), как это видно на рис. 32 слева.

Рис. 32. Использование компоненты TDBCtrlGrid
Покажем, как можно реализовать уточняющий поиск данных в таблице на примере данных об учителях. В форму FTeacher поместим обычный Edit и очистим ее свойство Text. Событие OnChange, возникающее при изменении текста в этой компоненте, свяжем со следующим кодом:
procedure TFTeacher. Edit1Change(Sender: TObject);
begin
DM. IBDSTeacher. Locate('FIO_TEACHER',Edit1.Text,[loPartialKey]);
end;
Следует подключить модуль DB (в предложении uses).
Здесь метод Locate(const KeyFields: String; const KeyValues: Variant; Options: TLocateOptions): Boolean ищет первую запись, удовлетворяющую критерию поиска, и если такая запись найдена, делает ее текущей. В этом случае в качестве результата возвращается True. Если запись не найдена, возвращается False. Список KeyFields указывает поле или несколько полей, по которым ведется поиск. В случае нескольких поисковых полей их названия разделяются точкой с запятой. Критерии поиска задаются в вариантном массиве KeyValues так, что i-е значение в KeyValues ставится в соответствие i-тому полю в KeyFields. Options позволяет указать режим поиска: loCaseInsentive - поиск ведется без учета высоты букв; loPartialKey - запись считается, удовлетворяющей условию поиска, если она содержит часть поискового контекста.
При использовании такого механизма необязательно вводить фамилию учителя полностью. Курсор НД будет приближаться к искомой записи по мере ввода символов в Edit1 (рис. 33).

Рис. 33. Использование механизма уточняющего поиска
Для построения различных графиков, использующих данные из таблиц или запросов, используется компонент DBChart, в котором выбирается вид графика и указывается источник данных.
2.6 Построение отчетов
В для работы со страницей QReport в Delphi 7 следует инсталлировать пакет dclqrt70.bpl (component/install package, кнопка Add – выбрать указанный пакет из каталога BIN Delphi 7).
Нам требуется создать следующие выходные документы:
1) Список отличников школы с указанием их процента в каждом классе.
2) Суммарную нагрузку учителей с подсчетом общей нагрузки по школе.
3) Подсчитать процент учеников в выбранном классе от общего количества учеников в школе.
Для выполнения двух первых отчетов откроем модуль данных DM и добавим в него два экземпляра компоненты TIBQuery (запросы). Первую назовем IBQOtl, вторую IBQSumNagr. IBQOtl будет вызывать созданный ранее просмотр (представление) BEST_PUPIL (ученики-отличники), IBQSumNagr - TOTAL_NAGR (суммарная нагрузка учителей).
Свойство Database данных компонент установим равным IBDBShool (из выпадающего списка), свойство Transaction - IBTransaction1.
Свойство SQL компоненты IBQOtl должно содержать оператор Select для выбора полей из просмотра BEST_PUPIL:
SELECT NUM_CLASS, NAMECLASS, FIO_PUPIL, BALL
FROM BEST_PUPIL
ORDER BY NAMECLASS
Свойство SQL компоненты IBQSumNagr должно содержать оператор Select для выбора полей из хранимой процедуры TOTAL_NAGR:
SELECT FIO, SUMNAGR FROM TOTAL_NAGR
ORDER BY FIO
Для подсчета процента отличников в каждом классе (первый запрос) добавим компоненту TIBStoredProc (назовем ее IBStoredP_Best), свойство Database установим равным IBDBShool, свойство Transaction - IBTransaction1. В свойство StoredProcName следует выбрать из выпадающего списка имя хранимой на сервере процедуры, возвращающей процент отличников (PROCENT_OTL). Процедура PROCENT_OTL содержит два параметра (свойство Param, доступное при активном компоненте IBTransaction1 и IBDBSchool): входной CL (имя класса; будет задаваться программно) и выходной PROC (процент отличников в классе).
Для подсчета процента учеников в выбранном классе от общего количества учеников в школе на сервере создана процедура PROC_PUPIL. Добавим в модуль данных еще один экземпляр компоненты TIBStoredProc (назовем ее IBStoredProcP, свойство Name). Остальные свойства настраиваются аналогично ранее настроенной компоненте IBStoredP_Best. Свойство StoredProcName устанавливается равным PROC_PUPIL.
К этому моменту модуль данных примет следующий вид (рис. 34):

Рис. 34. Модуль данных.
Создадим новую форму, назовем ее FReport1. Проектирование отчета аналогично работе с локальной базой данных. Прежде всего, поместим на созданную форму экземпляр компоненты TQuickRep со страницы QReport и через свойство DataSet свяжем ее с нужным запросом. Для выходного документа, связанного с информацией об отличниках классов с выдачей среднего балла каждого класса, воспользуемся созданным ранее запросом IBQOtl, который вызывает хранимую процедуру выбора.
При размещении компоненты на форме в ней появляется сетка отчета, в которой в дальнейшем располагают составные части отчета.
Компонента QuickRep имеет ряд свойств. Свойство Bands состоит из множества логических значений, которые определяют присутствие или отсутствие в отчете отдельных составляющих:
HasColumnHeader – заголовка столбцов
HasDetail – детальной информации
HasPageFooter – заключительной части страницы
HasPageHeader – заголовка страницы
HasSummary – заключительной части отчета
HasTitle – заголовка отчета
Составляющие отчета характеризуются различной частотой вывода. Так, заголовок отчета и заключительная часть отчета выводятся один раз; заголовок страницы, заголовки столбцов и заключительная часть страницы выводятся на каждой странице; заголовок группы выводится при изменении значения выражения, определяющего эту группу, в конце группы заключительная часть группы, а детальная информация выводится чаще всего.
Пункт меню главной формы Отличники свяжем с вызовом новой формой FReport1, на которой будем выводить отчет. Поставим в соответствие этому пункту следующие действия:
procedure TMain. N8Click(Sender: TObject);
begin
DM. IBQOtl. Open;//Открываем запрос
FReport1.QuickRep1.Preview;//Отображаем отчет
end;
Метод Preview компоненты TQuickRep выводит отчет в окно предварительного просмотра. Метод Print печатает отчет на принтере.
После просмотра отчета, следует закрыть запрос. Для этого свяжем событие AfterPreview отчета QuickRep1 со следующим кодом:
procedure TFReport1.QuickRep1AfterPreview(Sender: TObject);
begin
DM. IBQOtl. Close;//Закрываем запрос
end;
Компоненты TQRBand являются основными составными частями отчета и используются для размещения в них визуальных компонент, таких как TQRLabel, TQRDBText, TQRExpr, TQRGroup и др.
Для отображения в разделах отчета полей на них помещаются экземпляры компоненты QRLabel (статическое поле) с определением свойства Caption и QRDBText (поле НД). Для последней определяются свойства DataSet (имя запроса, формирующего НД) и DataField (имя поля НД).
Вместо компоненты QRDBText можно размещать компоненту QRExpr (выражение из полей НД) и определять его свойство Expression.
В заключительной части группы можно размещать выражения, содержащие итоговые (агрегатные) функции.
Итак, после размещения на форму компоненты QuickRep включим (положим равными True) следующие подсвойства в групповом свойстве Bands: HasColumnHeader, HasDetail и HasTitle (рис. 35):

Рис. 35. Свойства отчета
Так как в отчете требуется группировка учеников по классам, добавим в отчет по экземпляру компонент QRGroup и QRBand. Свойство BandType последней полагается равным rbGroupFooter, а свойство FooterBand компоненты QRGroup выбирается равным имени заключительной компоненты этой группы (в нашем случае QRBand1). Отчет примет вид, подобный примеру, изображенному на рис. 36.

Рис. 36. Состав отчета с группировкой данных.
Свойство Expression области GroupHeader, при изменении которого выводится заголовок группы, установим равным IBQOtl. NUM_CLASS (для этого можно воспользоваться построителем выражения). Поскольку свойство Expression не визуализирует значения выражения, необходимо разместить в группе Group Header компоненту QRDBText и определить значение ее свойства DataSet равным DM. IBQOtl, а свойства DataField - NAMECLASS.
Поместим заголовок отчета в область Title. Для этого воспользуемся компонентой QRLabel, в свойстве Caption которой введем «Лучшие ученики школы».
В области Group Header размещаются заголовки столбцов. Разместим здесь компоненты QRLabel c текстом «ФИО» и "Средний балл" соответственно.
В области детальной информации Detail разместим два экземпляра компоненты TQRDBText под соответствующими компонентами QRLabel. Их свойство DataSet установим равным DM. IBQOtl, а в качестве значения свойства DataField выберем FIO_pupil и Ball соответственно.
В подвале группы Group Footer разметим два экземпляра компоненты QRLabel. Текст первой - «Процент отличников в классе: ". Текст второй будет формироваться при печати подвала группы. Для этого выделим область подвала Group Footer, найдем событие BeforePrint и в его обработчик вставим код, в котором осуществим выполнение хранимой процедуры IBStoredP_Best, предварительно задав значение входному параметру CL:
procedure TFReport1.QRBand1BeforePrint
(Sender: TQRCustomBand; var PrintBand: Boolean);
var p:real;
s:string;
begin
DM. IBStoredP_Best. UnPrepare;
//Устанавливаем входной параметр CL хранимой процедуры
DM. IBStoredP_Best. ParamByName('cl').value:=
DM. IBQOtl. FieldValues['num_class'];
DM. IBStoredP_Best. Prepare; //Подготовка к выполнению
DM. IBStoredP_Best. ExecProc; //Выполнение процедуры
//Запоминаем значение выходного параметра процедуры
p:=DM. IBStoredP_Best. ParamByName('proc').Value;
str(p:6:2,s); //преобразуем его в строку
QRLabel5.Caption:=s; //помещаем в текст QRLabel5
end;
Компонент IBStoredProc также можно использовать для вызова хранимых процедур выбора.
Отчет на этапе проектирования примет следующий вид (рис. 37):

Рис. 37. Отчет на этапе проектирования
Если для каждой группы необходимо подсчитать агрегатную функцию (например, среднее или сумму), то в область Group Footer помещается экземпляр компоненты QRExpr, для которой соответствующим образом настраивается свойство Expression. Для сброса значения предыдущей группы (чтобы итоговое значение подсчитывалось по каждой группе, а не накапливался по всем группам) следует у компоненты QRExpr установить равным True свойство ResetAfterPrint.
После запуска приложения и открытия отчета получим экран вида (рис. 38):

Рис. 38. Отчет на этапе выполнения приложения.
Рассмотрим создание второго отчета. Для выдачи документа, отображающего суммарную нагрузку учителей, создадим новую форму FReport2, в которую поместим компоненту TQuickRep, свойство DataSet которой установим равным DM. IBQSumNagr.
Далее разметим дополнительные компоненты и настроим их так, как показано на следующем рисунке (рис. 39):

Рис. 39. Конструирование отчета о суммарной нагрузке
В свойство Expression компоненты QRExp, помещенной в область Summary (итоги), с помощью построителя выражения или вручную установим функцию подсчета суммы значения поля SUMNAGR: SUM(IBQSumNagr. SUMNAGR). Пункт меню главной формы Суммарная нагрузка учителей свяжем с новой формой FReport2, на которой будем выводить отчет. Поставим в соответствие этому пункту следующие действия:
procedure TMain. N9Click(Sender: TObject);
begin
DM. IBQSumNagr. Open;//Открываем запрос
FReport2.QuickRep1.Preview;//Отображаем отчет
end;
В обработчике события AfterPreview отчета закроем запрос:
DM. IBQSumNagr. Close;
Вид отчета, отображающего информацию о нагрузке выбранного учителя по каждому предмету с подсчетом суммарной нагрузки, показан ниже (рис. 40):

Рис. 40. Суммарная нагрузка учителей
Для реализации последнего (третьего) запроса нам потребуется создание еще одной формы(назовем ее FProc), на которую поместим экземпляры компонент TComboBox (выпадающий список), TLabel со страницы Standart и две кнопки Подсчитать и Закрыть (рис. 41).

Рис. 41. Форма для подсчета процента учеников в классе.
При отображении этой формы компонент ComboBox должен содержать названия всех классов школы. Для этого с событием OnShow этой формы свяжем следующий код:
procedure TFProc. FormShow(Sender: TObject);
begin
DM. IBDSClass. Open;//Открываем НД
DM. IBDSClass. First;//Указатель - на первую запись
ComboBox1.Clear;//Очистка списка
while not DM. IBDSClass. eof do //Цикл до конца НД
begin
//Добавление строки в список
ComboBox1.Items. Add(
DM. IBDSClass. FieldByName('nameclass').AsString);
DM. IBDSClass. Next;//Переход к следующей записи НД
end;
DM. IBDSClass. Close;//Закрытие таблицы
ComboBox1.ItemIndex:=0;//Установка на первый элемент
end;
Так как количество записей в таблице, содержащей классы, невелико, ведется построчное чтение данных и заполнение компонента. В случае большого числа записей, рационально использовать запрос, результаты которого можно показать в компоненте DBGrid, а затем проанализировать выбранную строку.
Обработчик события нажатия кнопки Подсчитать выглядит так:
procedure TFProc. Button1Click(Sender: TObject);
var p:real;
s:string;
begin
DM. IBStoredProcP. UnPrepare;
//Устанавливаем значение входного параметра процедуры
DM. IBStoredProcP. ParamByName('ncl').value:=ComboBox1.Text;
DM. IBStoredProcP. Prepare;//Подготовка к выполнению
DM. IBStoredProcP. ExecProc;//Выполнение хранимой процедуры
// Получаем значение выходного параметра процедуры
p:=DM. IBStoredProcP. ParamByName('proc_in_cl').Value;
str(p:6:2,s);//Переводим число p в строку s
MessageDlg('В '+ComboBox1.Text+' '+s+
'% от общего числа учеников', mtInformation,[mbYes],0);
end;
Свяжем с событием выбора пункта меню главной формы с вызовом формы FProc:
FProc. ShowModal;
Реакцией на нажатие кнопки Подсчитать является вывод информационного сообщения о проценте учеников выбранного класса (рис. 42).

Рис. 42. Вывод результата.
Если необходимо выполнять параметрический запрос (в свойстве SQL компоненты TIBQuery в предложении WHERE указываются параметры, имена которых предварены двоеточием), например:
SELECT * FROM CLASS WHERE BALL=:p
(вместо имени таблицы можно указывать имя просмотра). Для установки значения этого параметра следует выполнить следующее:
DM. IBQuery. ParamByName('p').Value:=Значение_параметра;
DM. IBQuery. Prepare;//Подготовка запроса к выполнению
DM. IBQuery. Open;//Открываем запрос
Более подробно работа с параметрическими запросами описана в методических указаниях к л/р №4 "Разработка локального приложения для работы с БД".
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 |



