Создание
перекрестного отчета с изменяющимся числом столбцов
Рассмотрим
возможности обработки событий в отчете на примере отчета "Выработка сотрудников".
Этот отчет строится на базе перекрестного запроса и показывает выработку сотрудников
отдела продаж за год по месяцам. Максимальное число столбцов в отчете — 14.
Первый столбец содержит фамилии сотрудников, следующие двенадцать столбцов —
выработку для каждого месяца и последний столбец — итоговый.
(Как выглядит
этот отчет, мы показывали в разд. "Перекрестные отчеты" гл. 10.)
В качестве
источника данных для такого запроса используется перекрестный запрос "Выработка
сотрудников", представленный на рис. 13.35.
Рис. 13.35.
Перекрестный запрос "Выработка сотрудников"
Поле "Отпускная
цена" является вычисляемым, и для его вычисления используется формула
CCur(CLng([Заказано].[Цена]*
[Количество]*(1-[Скидка])*100)/100)
Создание такого
отчета требует написания довольно большого числа процедур обработки событий.
В запросе
в качестве критерия выборки заказов указан год — 1998. Нужно вывести приглашение
пользователю, чтобы он, в свою очередь, мог ввести желаемый год. Это можно сделать
при открытии отчета. Сначала нужно создать базовый набор записей для отчета
и посчитать, сколько получилось столбцов в этом наборе. Следующая процедура
обрабатывает событие
Открытие
(On Open) отчета:
Private Sub Report_0pen(Cancel As Integer)
On
Error Resume Next
'
Создает базовый набор записей для отчета.
Dim intX As Integer
Dim qdf As QueryDef
Dim frm As form
Dim
StrSql As String
'
Связывает переменную с текущей базой данных.
Set
dbsReport = CurrentDb
'
Открывает запрос (объект QueryDef).
Set
qdf = dbsReport.QueryDefs("Выработка сотрудников")
'
Запрашивает год.
Год
= InputBox("Отчет за год:", "Год", 1998)
StrSql
=Left(qdf.SQL, InStr(qdf.SQL, "where") - 1) & " WHERE_ (((Year([ДатаИсполнения]))=
" & Год
&
"))" & Right(qdf.SQL, Len(qdf.SQL)
- InStr(qdf.SQL, "GROUP BY") + 1)
qdf.SQL
= StrSql
'
Открывает набор записей
Set
rstReport = qdf.OpenRecordset()
' Определяет количество столбцов в перекрестном запросе.
intColumnCount
= rstReport.Fields.Count
End
Sub
Здесь переменная
intColumnCount должна быть определена на уровне модуля формы, т. к. она используется
и другими процедурами данной формы.
Для событий
Форматирование
(On format) верхнего колонтитула (листинг 13.1) и области
данных отчета (листинг 13.2) необходимо определить процедуры, которые бы заполняли
поля заголовков и значений и скрывали неиспользуемые поля.
Листинг
13.1. Процедура обработки события
Форматирование
верхнего колонтитула
Private
Sub PageHeader()_format(Cancel As Integer,_
formatCount
As Integer)
Dim
intx As Integer
' Помещает заголовки столбцов в поля в верхнем колонтитуле.
Me("Head" + format(0)) = rstReport(0).Name
for
intX = 1 To intColumnCount - 1
Me("Head"
+ format(intX)) =_
MonthRus(CInt(rstReport(intX).Name))
Next
intX
' Вводит в ближайшее свободное поле заголовок "Итого".
Me("Head"
+ format(intColumnCount)) = "Итого"
'
Скрывает пустые поля в верхнем колонтитуле.
for
intX = (intColumnCount +1) То conTotalColumns - 1
Me("Head" + format(intX)).Visible = False
Next intX
End
Sub
В этой процедуре
используется функция MonthRus, которая по порядковому номеру месяца выдает его
название. Мы здесь не приводим текста этой функции, надеясь, что вы сможете
написать ее сами conTotalColumns — константа, которая описана на уровне модуля
и значение которой определяет максимальное число столбцов в отчете. В данном
примере conTotalColumns равна 14.
Листинг
13.2. Процедура обработки события
Форматирование
области данных
1
Private
Sub Detaill_format(Cancel As Integer,_ formatCount As Integer)
' Вводит значения в поля и скрывает пустые поля.
Dim
intX As Integer
' Проверяет, что не достигнут конец набора записей.
If
Not rstReport.EOF Then
'Помещает значения из набора записей в поля области данных
If
Me.formatCount = 1 Then
for
intX = 0 To intColumnCount - 1
'
Преобразует пустые значения в 0.
Me
("Col" + format(intX)} =_
xtabCnulls(rstReport(intX))
Next
intX
'
Скрывает неиспользуемые поля в области данных.
for
intX = intColumnCount + 1 То conTotalColumns - 1
Me("Col"
+ format(intX)).Visible = False Next intX
' Переходит к следующей записи в наборе. rstReport.Move
Next
End If
End If
End
Sub
Свойство formatCount
отчета содержит значение, равное количеству столбцов для форматирования, поэтому
в процедуре проверяется это свойство, и присвоение значений полям в области
данных выполняется, только если это значение не 0. В процедуре используется
также функция xtabCnulls, преобразующая пустое значение в 0.
Для события
Печать
(On Print) области данных отчета нужно создать процедуру, которая
бы суммировала значения по строке отчета, выводила полученное значение в последнем
столбце и, кроме того, добавляла эту сумму в массив итоговых значений по столбцам
(листинг 13.3). Массив итоговых значений по столбцам IngRgColumnTotal и переменная
IngReportTotal, определяющая общий итог, должны быть описаны на уровне модуля.
Кроме того, они должны быть инициализированы, т. е. им нужно присвоить начальные
значения 0. Это можно сделать в процедуре обработки события Загрузка (On Load)
отчета.
Листинг
13.3. Процедура обработки события
Печать
области данных
Private Sub Detaill_Print(Cancel As Integer, PrintCount As Integer)
Dim intX As Integer
Dim
IngRowTotal As Long
'
Вычисляет сумму по строке и добавляет ее к итоговому значению. ' по столбцу
и общему итогу
If Me.PrintCount = 1 Then IngRowTotal = 0
for
intX = 1 To intColumnCount - 1
' Начиная со столбца 1 (первый столбец с перекрестными
' значениями), вычисляет сумму по строке.
lngRowTotal = IngRowTotal + Me("Col" + format(intX))
'
Добавляет итоговое значение для текущего столбца.
IngRgColurenTotal(intX)
= IngRgColumnTotal(intX) +_
Me
("Col" + format(intX))
Next
intX
' Заносит сумму по строке в поле в области данных. Me("Col" + format(intColumnCount)) = IngRowTotal
' Прибавляет сумму по строке к общему итогу.
IngReportTotal = IngReportTotal + IngRowTotal
End If
End
Sub
Процедура
обработки события
Печать
(On Print) примечания отчета должна заполнить
поля примечания итоговыми значениями по столбцам из массива IngRgColumnTotal
(листинг 13.4).
Листинг
13.4. Процедура обработки события
Печать
примечания
Private
Sub ReportFooter4_Print(Cancel As Integer,_
PrintCount
As Integer)
Dim
intX As Integer
' Помещает суммы по столбцам в поля примечания.
for
intX = 1 То intColumnCount - 1
Me("Tot" + format(intX)) = IngRgColumnTotal(intX)
Next
intX
' Помещает общий итог в поле примечания.
Me("Tot" + format(intColumnCount)) = IngReportTotal
' Скрывает неиспользуемые поля в примечании отчета.
for
intX = intColumnCount + 1 То conTotalColumns - 1
Me("Tot" + format(intX)).Visible = False
Next intX
End
Sub
Для корректной
работы нужно еще добавить две небольшие процедуры в свойства отчета:
Ниже приведены обе эти процедуры (листинги 13.5 и 13.6).
Листинг
13.5. Процедура обработки события
Закрытие отчета
Private
Sub Report_Close()
On
Error Resume Next
rstReport.Close
End
Sub
Листинг
13.6. Процедура обработки события
Отсутствие данных отчета
Private
Sub Report_NoData(Cancel
As
Integer)
MsgBox
"He найдены записи, удовлетворяющие указанным_
условиям.",
vbExclamation, "Записи не найдены"
rstReport.Close Cancel = True
End Sub