Сложные заголовки
Изначально наш грид выглядит вот так:
Для того, чтобы добавить объединяющие заголовки для существующих, совершенно явно следует увеличить по высоте область заголовков грида.
И в нужном месте дорисовать самим объединяющую часть заголовка.
Реализация описанной методики в нашем наследнике
TexDBGrid:
- Введем свойство, которое будет включать/выключать режим сложных заголовков.
TexDBGrid = class(TDBGrid) private FSubHeader : Boolean; // подзаголовки
... published Property SubHeader : Boolean read FSubHeader write SetSubHeader; |
Именно это свойство будет регулировать высоту области заголовков.
... Const TITLE_SUBHEADER = 2; TITLE_DEFAULT = 1; ... //*******************************************************
procedure TexDBGrid.CalcTitle; begin RowHeights[0] := 19 * FTitleLines ; end; //*******************************************************
procedure TexDBGrid.SetSubHeader(const Value: Boolean); begin FSubHeader := Value;
IF FSubHeader Then FTitleLines:=TITLE_SUBHEADER Else FTitleLines:=TITLE_DEFAULT; CalcTitle; end; |
- В метод TexDBGrid.DrawCell добавляем обработку
IF FSubHeader Then Begin // Рисуем объединяющий заголовок Header к мелким заголовкам Title
DrawSubHeader(DataCol, Canvas);
// Рисуем заголовки Title
FRect:=ARect; FRect.Top:=RectHeight(ARect) div FTitleLines;
DrawTitleCell(FRect,Columns[DataCol]); End Else DrawTitleCell(FRect,Columns[DataCol]); |
Здесь рисование заголовка разбито на две процедуры: DrawSubHeader и DrawTitleCell. Где DrawTitleCell рисует в прямоугольнике 3D-окантовку, заливает его цветом FixedCols и вписывает текст. То есть имитирует обычный заголовок колонки. А вот на процедуре DrawSubHeader остановимся поподробнее.
- Для того, чтобы нарисовать объединяющий заголовок для нескольких колонок, нужно получить прямоугольник (TRect), который объединяет эти колонки и текст, который следует писать в объединяющем заголовке. Для обеспечения гибкой настройки создадим два свойства:
published Property OnGetHeaderText : TOnGetHeaderText read FOnGetHeaderText write FOnGetHeaderText; Property OnGetHeaderRect : TOnGetHeaderRect read FOnGetHeaderRect write FOnGetHeaderRect; |
С помощью этих свойств можно будет настраивать обработчики соответствующих событий.
Procedure DrawSubHeader(ACol : Integer; Canvas : TCanvas); Var HRect : TRect; Begin // Получаем прямоугольник, объединяющий несколько колонок, // для которых рисуем сложный заголовок
HRect:=GetHeaderRect(ACol); // По высоте берем только часть прямоугольника // так как вторая часть — обычный заголовок
HRect.Bottom:=RectHeight(HRect) div TITLE_SUBHEADER; Canvas.FillRect(HRect);
// Вписываем текст, // который получаем методом GetHeaderText
InflateRect(HRect,-1,-1); WriteText(Canvas, HRect, GetHeaderText(ACol) , taCenter);
// Рисуем 3D-окантовку Paint3dRect(Canvas.Handle,HRect); End; |
Внутри методов GetHeaderRect и GetHeaderText будут вызываться обработчики событий FOnGetHeaderRect и FOnGetHeaderText.
При этом, следует помнить, что в каждый момент могут быть видны не все колонки из объединенных в блок. Воспользуемся функцией TCustomDBGrid.CalcTitleRec, которая возвращает прямоугольник для определенной колонки и строки. Если в данный момент эта колонка не видна, то будет возвращен нулевой прямоугольник.
Function TexDBGrid.GetHeaderRect(ACol : Integer) : TRect; Var MasterCol : TColumn; Index,Shift , Count,i : Integer; Begin // Если в опциях отключен показ сетки, это нужно учесть при расчете // общего прямоугольника
IF [dgColLines] * Options = [dgColLines] Then Shift:=1 Else Shift:=0;
Index:=ACol; Count:=1; // получаем информацию для текущей колонки грида: // в какой объединяющий блок она входит // Index — с какой колонки начинается объединяющий блок // Count — сколько колонок он включает
IF Assigned(FOnGetHeaderRect) Then FOnGetHeaderRect(ACol, Index, Count);
IF Index+Count-1 > Columns.Count-1 Then Begin Index:=ACol; Count:=1; End;
// В результате нужно получить прямоугольник, состоящий из // всех, включенных в объединенный блок колонок
Result:=CalcTitleRect(Columns[Index],0,MasterCol);
For i:=Index+1 To Index + Count -1 Do Result.Right:=Result.Right + RectWidth(CalcTitleRect(Columns[i] ,0,MasterCol)) + Shift;
End; |
И для примера покажем, как именно могут использоваться обработчики событий получения объединяющего прямоугольника и текста при использовании сложных заголовков:
Const GeoColumns = 3; ParamColumns = 2; ... //---------------------------------------------------------------------------------------- // Получить для текущей колонки информацию о том, в какое объеденение колонок она попадает //----------------------------------------------------------------------------------------
procedure TfExDBG.GetHeaderRect(ACol: Integer; var IndexStart, Count: Integer); begin IF ACol < GeoColumns Then Begin IndexStart:=0; Count:=GeoColumns; End Else Begin IndexStart:=GeoColumns; Count:=ParamColumns; End end; //---------------------------------------------------------------------------------------- // Получить для текущей колонки текст заголовка объеденени //----------------------------------------------------------------------------------------
procedure TfExDBG.GetHeaderText(ACol: Integer; var Text: String); begin IF ACol < GeoColumns Then Text:='География' Else Text:='Параметры'; end; //----------------------------------------------------------------------------------------
|
Предложенный способ просто один из возможных, он не позволяет настраивать параметры объединяющих заголовков в design-time, рассчитан на использование двухуровневых заголовков и предполагает наличие сложных заголовков у всех колонок грида.
Например, для того, чтобы сделать так, как показано на рисунке ниже, следует свойство SubHeader привязывать не ко всему гриду, а к каждой его колонке.
Рассказать о реализации всех вариантов сложных заголовков не представляется возможным. Изучив наши примеры, Вы можете сами совершенствовать новый грид, по собственному усмотрению.
Содержание раздела