Управление кросс-таблицей из скрипта

       Если визуальных средств настройки таблицы недостаточно, можно использовать скрипт для тонкой настройки внешнего вида таблицы. Объект "Кросс-таблица" имеет следующие события:

 

Событие

Описание

OnAfterPrint

Событие вызывается после печати таблицы.

OnBeforePrint

Событие вызывается перед печатью таблицы.

OnCalcHeight

Событие вызывается перед подсчетом высоты строки таблицы. Обработчик события может вернуть нужное значение высоты или 0 для того, чтобы скрыть строку.

OnCalcWidth

Событие вызывается перед подсчетом ширины столбца таблицы. Обработчик события может вернуть нужное значение ширины или 0 для того, чтобы скрыть столбец.

OnPrintCell

Событие вызывается перед отображением ячейки таблицы. Обработчик события может изменить оформление или содержимое ячейки.

OnPrintColumnHeader

Событие вызывается перед отображением заголовка колонок таблицы. Обработчик события может изменить оформление или содержимое ячейки заголовка.

OnPrintRowHeader

Событие вызывается перед отображением заголовка строк таблицы. Обработчик события может изменить оформление или содержимое ячейки заголовка.

 

       В событиях удобно использовать следующие методы объекта "Кросс-таблица":

 

Метод

Описание

function ColCount: Integer

Возвращает количество колонок в таблице.

function RowCount: Integer

Возвращает количество строк в таблице.

function IsGrandTotalColumn

(Index: Integer): Boolean

Возвращает True, если колонка с указанным номером является итоговой.

function IsGrandTotalRow

(Index: Integer): Boolean

Возвращает True, если строка с указанным номером является итоговой.

function IsTotalColumn

(Index: Integer): Boolean

Возвращает True, если колонка с указанным номером является колонкой промежуточных итогов.

function IsTotalRow

(Index: Integer): Boolean

Возвращает True, если строка с указанным номером является строкой промежуточных итогов.

procedure AddValue(const Rows, Columns, Cells:

array of Variant)

Добавляет значение в таблицу.

 

       Рассмотрим на примере, каким образом можно выделить третью колонку цветом фона (в нашем примере – это данные за ноябрь 1999 года). Для этого выделим кросс-таблицу и создадим обработчик события OnPrintCell:

 

Pascal script:

 

procedure Cross1OnPrintCell(Memo: TfrxMemoView;

RowIndex, ColumnIndex, CellIndex: Integer;

RowValues, ColumnValues, Value: Variant);

begin

if ColumnIndex = 2 then

   Memo.Color := clRed;

end;

 

C++ Script:

 

void Cross1OnPrintCell(

TfrxMemoView Memo,

int RowIndex,

int ColumnIndex,

int CellIndex,

Variant RowValues,

Variant ColumnValues,

Variant Value)

{

if (ColumnIndex == 2) { Memo.Color = clRed; }

}

 

       Мы увидим следующий результат:

 

_img216

 

       Чтобы выделить цветом заголовок колонки, создадим обработчик события OnPrintColumnHeader:

 

Pascal script:

 

procedure Cross1OnPrintColumnHeader(Memo: TfrxMemoView;

HeaderIndexes, HeaderValues, Value: Variant);

begin

if (VarToStr(HeaderValues[0]) = '1999') and

   (VarToStr(HeaderValues[1]) = '11') then

   Memo.Color := clRed;

end;

 

C++ Script:

 

void Cross1OnPrintColumnHeader(

TfrxMemoView Memo,

Variant HeaderIndexes,

Variant HeaderValues,

Variant Value)

{

  if ((VarToStr(HeaderValues[0]) == "1999") &&

     (VarToStr(HeaderValues[1]) == "11"))

{

   Memo.Color = clRed;

}

}

 

       Результат:

 

_img217

 

       Поясним работу скриптов. Обработчик события OnPrintCell вызывается перед печатью ячейки, которая содержится в теле таблицы (при печати ячеек из заголовка таблицы вызывается обработчик OnPrintColumnHeader или OnPrintRowHeader). При этом в обработчик OnPrintCell передается ссылка на объект "Текст", который представляет собой ячейку таблицы (параметр Memo), и "адрес" ячейки в двух вариантах: номер строки, колонки и ячейки (последнее актуально, если в вашей таблице многоуровневые ячейки) в параметрах RowIndex, ColumnIndex, CellIndex соответственно. Второй вариант "адреса" – это параметры RowValues и ColumnValues. Параметр Value – это содержимое ячейки.

 

       Для определения "адреса" вы можете использовать как первый вариант (RowIndex, ColumnIndex), так и второй (RowValues, ColumnValues) – что удобнее в конкретном случае. В нашем случае нужно было выделить третью колонку – поэтому удобнее анализировать первый вариант. Т.к. нумерация колонок и строк начинается с 0, проверка ColumnIndex = 2 позволила нам определить 3-ю колонку. Можно было поступить иначе, анализируя нужную колонку по ее данным (нам нужен 11 месяц 1999 года):

 

Pascal script:

 

procedure Cross1OnPrintCell(Memo: TfrxMemoView;

RowIndex, ColumnIndex, CellIndex: Integer;

RowValues, ColumnValues, Value: Variant);

begin

if (VarToStr(ColumnValues[0]) = '1999') and

   (VarToStr(ColumnValues[1]) = '11') then

   Memo.Color := clRed;

end;

 

C++ Script:

 

void Cross1OnPrintCell(

TfrxMemoView Memo,

int RowIndex,

int ColumnIndex,

int CellIndex,

Variant RowValues,

Variant ColumnValues,

Variant Value)

{

if ((VarToStr(ColumnValues[0]) == "1999") &&

    (VarToStr(ColumnValues[1]) == "11"))

{

   Memo.Color = clRed;

}

}

 

       Значения, передаваемые в параметрах RowValues и ColumnValues – это массивы типа Variant с нулевой базой. Нулевой элемент – это значение верхнего уровня заголовка таблицы, первый – значение следующего уровня и т.д. В нашем случае ColumnValues[0] – это года, ColumnValues[1] – месяцы.

 

       Зачем нужно преобразование VarToStr? Это гарантирует отсутствие ошибок приведения типов. FastReport при операциях с типом Variant пытается автоматически приводить строки в числовой формат, что в нашем случае вызовет ошибку при попытке приведения значения столбцов 'Total' и 'Grand Total'.

 

       Обработчик события OnPrintColumnHeader вызывается при печати ячеек заголовка столбца. Набор параметров похож на параметры обработчика OnPrintCell, но здесь "адрес" ячейки (параметры HeaderIndexes, HeaderValues) передается иначе. Параметр HeaderValues возвращает те же значения, что и параметры ColumnValues, RowValues в обработчике OnPrintCell. Параметр HeaderIndexes также является массивом значений типа Variant и содержит адрес ячейки заголовка в другой форме: нулевой элемент – это порядковый номер верхнего уровня заголовка таблицы, первый – номер следующего уровня и т.д. Принцип нумерации ячеек заголовка станет понятен, если взглянуть на рисунок:

 

_img218

 

       В нашем случае удобно анализировать значение HeaderValues, но можно написать и такой обработчик:

 

Pascal script:

 

procedure Cross1OnPrintColumnHeader(Memo: TfrxMemoView;

HeaderIndexes, HeaderValues, Value: Variant);

begin

if (HeaderIndexes[0] = 0) and (HeaderIndexes[1] = 2) then

   Memo.Color := clRed;

end;

 

C++ Script:

 

void Cross1OnPrintColumnHeader(

TfrxMemoView Memo,

Variant HeaderIndexes,

Variant HeaderValues,

Variant  Value)

{

if ((HeaderIndexes[0] == 0) && (HeaderIndexes[1] == 2)) { Memo.Color = clRed; }

}

 

 

       С помощью обработчиков событий OnCalcWidth, OnCalcHeight можно управлять шириной и высотой строк и столбцов таблицы. Покажем на примере, как увеличить ширину колонки, соответствующей 11 месяцу 1999 года. Для этого создадим обработчик события OnCalcWidth:

 

Pascal script:

 

procedure Cross1OnCalcWidth(ColumnIndex: Integer;

ColumnValues: Variant; var Width: Extended);

begin

if (VarToStr(ColumnValues[0]) = '1999') and

   (VarToStr(ColumnValues[1]) = '11') then

   Width := 100;

end;

 

C++ Script:

 

void Cross1OnCalcWidth(

int ColumnIndex,

variant ColumnValues,

Extended &Width)

{

if ((VarToStr(ColumnValues[0]) == "1999") &&

   (VarToStr(ColumnValues[1]) = "11"))

   {

     Width = 100;

   } 

}

 

       Результат:

 

_img219

 

       Чтобы скрыть колонку, в нашем примере достаточно вернуть Width := 0. Заметим, что при этом суммы пересчитываться не будут – матрица к этому моменту уже заполнена значениями.