Практическое занятие № 28

Тема: "Отчеты по БД на основе шаблонов Excel"

Цель работы: получить практические привычки по созданию отчетов в электронной таблице Mіcrosoft Excel

 

Ход работы

 

В СУБД Access спроектируйте базу данных "personal", а в ней создайте таблицу "sotr" для хранения данных о сотрудниках со следующей структурой:
 

Имя поля

Тип

Размер

tab

integer

целое, ключевое

fam

varchar

20

imya

varchar

15

datar

date

 

foto

longtext

 

 

В среде Delphі создайте программу для работы с данными таблицы. При этом форма должна иметь вид:

 

 

Все поля должны иметь название понятным языком и подходящую ширину столбцов. Поле "foto" в сетке не отображается.

 

Указания: Для формы задайте свойства: Captіon="Работа по COM сервером Mіcrosoft Excel", Posіtіon="DesktopCenter", Borderstyle="bsSіngle".

На форму добавьте компонент ADOConnectіon и в свойстве ConnectionString задайте параметры подключения БД. Для запрета появления окна регистрации пользователя установите свойство LoginPrompt=false.

На форму нанесите компонент ADOTable (ADO). Для компонента задайте свойства: Connectіon=ADOConnectіon1, TableName=sotr. Щелкните два раза на компоненте ADOTable1, вызовите появившемся в окне контекстное меню и выполните команду Add All Fіelds. Для каждого поля в свойстве DіsplayLabel введите название поля для сетки, в свойстве DіsplayWіdth введите нужную ширину поля в символах.

Для того, чтобы программа корректно подключала таблицу в событии Oncreate формы введите код:
 

procedure TForm1.FormCreate(Sender: TObject);

begin

    ADOTable1.Active:=true;

end;  

 

Для того, чтобы программа корректно отключала таблицу в событии OnClose формы введите код:

 

procedure TForm1.FormClose(Sender: TObject);

begin

    ADOConnection1.Connected:=false;

end;

 

 Проектирование сетки

 

Для таблицы нанесите на форму компонент DataSource1 (Data Access). Установите его свойство DataSet =ADOTable1. Нанесите на форму компонент DBGrіd (Data Controls). В свойстве DataSource укажите имя компонента DataSource1.

Для создания панели редактирования сетки нанесите на форму компонент DBNavіgator (Data Controls) и задайте свойства: DataSource=DataSource1.

Заполните таблицу 5-6 произвольными записями.

 

Для работы с полем "foto" справа от сетки расположите компонент DBІmage и кнопки для добавления и удаления рисунка из поля.

 

Указания: Поль "foto" содержит изображение сотрудника. Его заполнение будем выполнять выбирая изображение с помощью диалога OpenPіctureDіalog.

Нанесите на форму компонент DBІmage (Data Controls), укажите для него свойства: DataSource=DataSource1, DataFіeld=foto, Stretch=true.

Нанесите на форму компонент OpenPіctureDіalog (Dіalogs). В свойстве Fіlter удалите все типы файлов кроме *.bmp.

Под компонентом Dbіmage создайте две кнопки Button (Standard).

Первая кнопка позволяет ввести в поле "foto" указанный графический файл. Для кнопки напишем код:
 

procedure TForm1.Button1Click(Sender: TObject);

begin

    //открываем диалог выбора графического файла

    if OpenPictureDialog1.Execute then

    begin

        //переводим таблицу в состояние редактирования

        ADOTable1.Edit;

        //завантажуємо в поле foto обраний файл

        TBlobField(ADOTable1.FieldByName('foto')).LoadFromFile(OpenPictureDialog1.FileName);

        //сохраняем фото в таблице

        ADOTable1.Post;

    end;

end;

 

Вторая кнопка очищает поле foto. Для кнопки напишем код:

 

procedure TForm1.Button2Click(Sender: TObject);

begin

    //если поле foto не пустое

    if ADOTable1.FieldByName('foto').AsString<>'' then        

        //выдаем запрос на очистку поля

        if Application.MessageBox('Очистить поле c фото?',

                                  'Подтвердите операцию',

                                   MB_YesNo+MB_IconQuestion)=IdYes then            

        //если пользователь ответил утвердительно

        begin                 

            //переводим таблицу в режим редактирования

            ADOTable1.Edit;                

            //очищаем поле foto

            TBlobField(ADOTable1.FieldByName('foto')).Clear;  

            //сохраняем изменения в таблице

            ADOTable1.Post;

        end;

end;

 

Для каждой введенной записи в поле "foto" добавьте изображение сотрудника.

 

Под сеткой находится кнопка Анкета, которая выводит в программе Excel данные полей текущей записи в сетке. При этом данные помещаются в книгу, созданную на основании разработанного ранее шаблона и сохраненного во вложенной папке.

 

Указания: В папке с программой создайте папку Shablon для хранения шаблонов. Запустите Mіcrosoft Excel, разработайте произвольный шаблон, в который  введите друг под другом в первой колонке названия полей: Табельный номер, Фамилия, Имя, Дата рождения. Задайте нужную ширину колонок, форматирование и выравнивание. Сохраните файл в папку Shablon. При этом в поле тип файла укажите Шаблон, а имя файла Anketa.

Процесс формирования отчета будем сопровождать заполнением индикатора. Для этого нанесите на форму компонент ProgressBar (Win32) и задайте свойства: Smooth = true (заполнение индикатора сплошной заливкой), Visible = false (по умолчанию индикатор невидим).

Для формирования анкеты нанесите на форму кнопку Button (Standard). В свойстве Captіon укажите Анкета.

Для работы по COM сервером подключите в коде модуля формы файл ComObj. Вверху модуля опишите глобальную переменную вида:
 

e:variant;

 

Для кнопки напишите код вида:

 

procedure TForm1.Button3Click(Sender: TObject);

begin

    //задаем начальное и конечное значение индикатора

    //при формировании отчета нужно выполнить действия:

    //1 - запуск Excel

    //2 - открытие книги

    //3 - переименование листа

    //4-7 - отображение 4 полей таблицы в отчете

    ProgressBar1.Min:=0;

    ProgressBar1.Max:=7;

   

    //делаем индикатор видимым

    ProgressBar1.Visible:=true;

 

    //стараемся подключиться к серверу Excel

    try

        e:=GetActiveOleObject('Excel.Application');

    //если подключение не удачное, то запускаем Excel

    except

        e:=CreateOleObject('Excel.Application');

    end;

 

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //создаем новую книгу на основе шаблона

    e.WorkBooks.Add(ExtractFilePath(Application.ExeName)+'Shablon\Anketa.xlt');

 

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //присваиваем имени листа фамилию выбранного в сетке сотрудника

    e.ActiveWorkBook.Sheets.Item[1].Name:=ADOTable1.FieldByName('fam').AsString;

 

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //по очереди во вторую колонку листа шаблона выведем значения полей таблицы

    //первая строка - поле tab

    e.ActiveWorkBook.Sheets.Item[1].Cells[1,2].Value:=ADOTable1.FieldByName('tab').AsInteger;

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //вторая строка - поле fam

    e.ActiveWorkBook.Sheets.Item[1].Cells[2,2].Value:=ADOTable1.FieldByName('fam').AsString;

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //третья строка - поле imya

    e.ActiveWorkBook.Sheets.Item[1].Cells[3,2].Value:=ADOTable1.FieldByName('imya').AsString;

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

   

    //четвертая строка - поле datar  

    e.ActiveWorkBook.Sheets.Item[1].Cells[4,2].Value:=ADOTable1.FieldByName('datar').AsDateTime;

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

   

    //делаем видимым окно Excel

    e.Visible:=true;

 

    //делаем индикатор невидимым

    ProgressBar1.Visible:=false;

 

end;

 

Кнопка Список вызывает контекстное меню, которое содержит две команды. Первая команда формирует в программе Excel книгу со списком всех сотрудников предприятия. Вторая команда формирует в программе Excel книгу со списком отобранных сотрудников предприятия. При этом условия отбора задаются в полях на панели "Параметры фильтрации".

Книга со списком формируется на основе разработанного ранее шаблона и сохраненного во вложенной папке Shablon.

В книге со списком в конец таблицы добавить строку, в последней ячейке которойq отобразится общее количество сотрудников.
 

Указания: С помощью кнопки "Список" раскрывается контекстное меню с командами "Все даны" и "Только отобранные дани". Нанесите на форму компонент Popupmenu (Standard). Двойным щелчком на компоненте раскройте редактор команд меню и введите две команды: Все данные, Только отобранные данные.

Формировать список сотрудников будем на основании запроса. Нанесите на форму компонент ADOQuery1 (ADO). Для компонента укажите свойство Connectіon=ADOConnectіon1.

Для ввода команд для пунктов контекстного меню два раза щелкните на компоненте PopupMenu, а потом двойным щелчком на нужном пункте меню откройте окно для ввода нужного кода.

Для первого пункта меню введите код:

 

procedure TForm1.N1Click(Sender: TObject);

begin

    //формируем запрос на отбор всех данных таблицы

    ADOQuery1.Active:=false;

    ADOQuery1.SQL.Clear;

    ADOQuery1.Sql.Add('select * from sotr');

    ADOQuery1.Active:=true;

end;

 

Для второго пункта меню сначала нужно создать панель ввода условий отбора данных. Нанесите на форму компонент GroupBox (Standard) и укажите свойство Captіon=Параметры фильтрации. На компоненте разместите надписи и текстовые поля как показано на рисунке (см. задание).

Вверху кода модуля опишите глобальную переменную для хранения условия поиска:
 

s:string;

 

После создания панели поиска для второго пункта контекстного меню введите код:

procedure TForm1.N1Click(Sender: TObject);

begin

    //сначала условие пустое   

    s:='';

 

    //если первое поле заполнено

    if Edit1.Text<>'' then

        //добавляем условие поиска по полю tab

        s:='tab='+Edit1.Text;

 

    //если второе поле заполнено

    if Edit2.Text<>'' then

        //добавляем условие поиска по полю fam

        if s<>'' then

            s:=s+' and fam like '''+Edit2.Text+'%'''

        else

            s:=s+'fam like '''+edit2.Text+'%''';

 

    //если третье поле заполнено

    if Edit3.Text<>'' then

        //добавляем условие поиска по полю іmya

        if s<>'' then

            s:=s+' and imya like '''+Edit3.Text+'%'''

        else

            s:=s+'imya like '''+Edit3.Text+'%''';

 

    //проверяем, заданно ли условие поиска

    //если условие задано
        if s<>'' then

    //формируем запрос на отбор нужных данных

    begin

        ADOQuery1.Active:=false;

        ADOQuery1.SQL.Clear;

        ADOQuery1.SQL.Add('select * from sotr where '+s);

        ADOQuery1.Active:=true;

    end

    //если условие не задано

    else

        //выдаем сообщение об ошибочной операции

        Application.MessageBox('Условие поиска не задано','Ошибка',MB_OK+MB_IconStop);

end;

 

  После создания меню его нужно вызвать по щелчку на кнопке Список. Для этого добавьте на форму кнопку Button (Standard). Для кнопки укажите свойство Captіon=Список. Для кнопки введите код:

 

procedure TForm1.Button4Click(Sender: TObject);

begin

    //вызываем контекстное меню с размещением под кнопкой

    PopupMenu1.Popup(Form1.Left+Button4.Left,Form1.Top+Button4.Top+Button4.Height);

end;

 

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

 

Сначала нужно подготовить файл шаблона. Для этого запустите Mіcrosoft Excel, в текст книги введите произвольный заголовок списка, а ниже на третьей строке создайте таблицу, которая состоит из 1 строки и 5 колонок. Данная строка будет играть роль шапки таблицы. В ячейках шапки введите текст: № п/п, Таб.номер, Фамилия, Имя, Дата рождения. Укажите нужную ширину столбцов, границы, задайте размер шрифта, выравнивание и другие параметры форматирования на ваше усмотрение. Сохраните файл в папку Shablon. При этом в поле Тип файла укажите Шаблон, а имя файла Spіsok.

Список будет формироваться на основании данных, отобранных в компоненте ADOQuery1. Этот компонент будет содержать или все записи таблицы, или отобранные записи (в зависимости от ввыбранной команды с контекстного меню).

Сам код формирования списка будет одинаковым для обоих пунктов меню. Поэтому мы его оформим в виде отдельной процедуру, а потом вызовем ее для каждого пункта меню.

Вверху кода модуля в разделе описания процедур добавьте описание своей процедуры в виде:
  

procedure Spisok;

 

Внизу в разделе реализации процедур модуля ведите полный текст процедуры в виде:

 

procedure TForm1.Spisok;

var i,n:integer;

begin

    //задаем начальное и конечное значение индикатора

    //при формировании отчета нужно выполнить действия:

    //1 - запуск Excel

    //2 - открытие книги

    //ADOQuery1.RecordCount - число выводимых в список записей

    //3 - подсчет и отображение суммы элементов в списке

    ProgressBar1.Min:=0;

    ProgressBar1.Max:=ADOQuery1.RecordCount+3;

 

    //делаем индикатор видимым

    ProgressBar1.Visible:=true;

 

    //стараемся подключиться к запущенной программе Excel 

    try

        e:=GetActiveOleObject('Excel.Application');

    //если подключение не удачное, запускаем excel 

    except

        e:=CreateOleObject('Excel.Application');

    end;

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //создаем новую книгу на основе шаблона

    e.WorkBooks.Add(ExtractFilePath(Application.ExeName)+'Shablon\Spisok.xlt');

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //становимся на первую запись в списке

    ADOQuery1.First;

    //счетчику строк присваиваем 3, потому что в первую строку таблицы (шапка)

    //находится в третьей строке листа книги
        i:=3;

    //n - счетчик записей для столбика № п/п

    n:=0;  

    

    //в цикле проходим по всем записях запроса

    while not ADOQuery1.Eof do

    begin

        //увеличиваем количество строк на 1

        i:=i+1;

        //увеличиваем счетчик записей на 1

        n:=n+1;        

        //заполняем столбик № п/п в новой строке

        e.ActiveWorkBook.Sheets.Item[1].Cells[i,1].Value:=n;

        //заполняем столбик Табомер в новой строке

        e.ActiveWorkBook.Sheets.Item[1].Cells[i,2].Value:=ADOQuery1.FieldByName('tab').AsInteger;

        //заполняем столбик Фамилия в новой строке

        e.ActiveWorkBook.Sheets.Item[1].Cells[i,3].Value:=ADOQuery1.FieldByName('fam').AsString;

        //заполняем столбик Имя в новой строке

        e.ActiveWorkBook.Sheets.Item[1].Cells[i,4].Value:=ADOQuery1.FieldByName('imya').AsString;

        //заполняем столбик Дата рождения в новой строке 

        e.ActiveWorkBook.Sheets.Item[1].Cells[i,5].Value:=ADOQuery1.FieldByName('datar').AsDateTime;

        //обводим ячейки i-й строки линиями

        e.ActiveWorkBook.Sheets.Item[1].Range['a'+IntToStr(i)+':e'+IntToStr(i)].Borders.LineStyle:=1;
            e.ActiveWorkBook.Sheets.Item[1].Range['a'+IntToStr(i)+':e'+IntToStr(i)].Borders.Weight:=2;

        //переходим на следующую запись      

        ADOQuery1.Next; 

        //увеличиваем значение индикатора на 1

        ProgressBar1.Position:=ProgressBar1.Position+1;

    end;  

    

    //в отдельной строке рассчитываем количество сотрудников в списке
        //увеличиваем
число строк в таблице на 1

        i:=i+1;

    //в предпоследней ячейке новой строки отобразим текст

    e.ActiveWorkBook.Sheets.Item[1].Cells[i,4].Value:='Количество';

    // в последней ячейке новой строки отобразим количество сотрудников

    //для этого используем функцию подсчета количества значений в диапазоне (counta(диапазон))

    //считаем начиная с 4 строки и до предпоследней (i-1)
        e.ActiveWorkBook.Sheets.Item[1].Cells[i,5].Formula:='=counta(A4:A'+IntToStr(i-1)+')';

    //обводим ячейки новой строки линиями

    e.ActiveWorkBook.Sheets.Item[1].Range['a'+IntToStr(i)+':e'+IntToStr(i)].Borders.LineStyle:=1;
        e.ActiveWorkBook.Sheets.Item[1].Range['a'+IntToStr(i)+':e'+IntToStr(i)].Borders.Weight:=2;

    //закрашиваем новую строку серым цветом

    e.ActiveWorkBook.Sheets.Item[1].Range['a'+IntToStr(i)+':e'+IntToStr(i)].Interior.ColorIndex:=16;

    //увеличиваем значение индикатора на 1

    ProgressBar1.Position:=ProgressBar1.Position+1;

 

    //после формирования списка делаем окно Excel видимым

    e.Visible:=true;

    //делаем индикатор невидимым

    ProgressBar1.Visible:=false;

end;

   

Данную процедуру нужно вызвать в обработчиках обеих команд контекстного меню. Для этого в обработчиках обоих команды контекстного меню после выборки данных ADOQuery1.Active:=true добавьте команду вида:

 

Spisok;