В отличие от рисования нестандартных заголовков при использовании стандартного компонента TDBGrid, в наследнике такое рисование выполняется проще, так как в компоненте есть виртуальный метод DrawCell, который вызывается для всех ячеек грида, а не только для содержащих данные. Рисование нестандартных заголовков в этом случае выполняется в перекрытом методе DrawCell в наследнике.
Кроме того, так как метод DrawCell вызывается гридом при любой его перерисовке, затрагивающей клиентскую область окна, нет нужды отслеживать, какие заголовки были нарисованы или обновлять все окно грида при скроллинге. Наше рисование будет вызвано только тогда, когда возникнет реальная необходимость в отрисовке области заголовков грида.
procedure THSDBGrid.DrawCell(ACol, ARow: Integer; ARect: TRect; State: TGridDrawState); var TitleText : String; { Полный заголовок } Titles : array of String; { Части заголовка } { Разбиение полного заголовка на части с возвращением числа получившихся частей } function SplitTitle : Integer; const TitleSeparator = ' '; { Можно этот символ вынести в published property } var CurPos, J: Integer; CurStr: string; begin SetLength(Titles, FTitleLines); { Определяем, сколько реально строк присутсвует в заголовке. Просто считается количество символов TitleSeparator } J := 0; CurStr:= TitleText; repeat CurPos:= Pos(TitleSeparator, CurStr); if (CurPos > 0) and (J < Pred(FTitleLines)) then begin Titles[J] := Copy(CurStr, 1, Pred(CurPos)); CurStr:= Copy(CurStr, CurPos+Length(TitleSeparator), Length(CurStr)-CurPos-Length(TitleSeparator)+1); Inc(J); end else begin Titles[J] := CurStr; if J >= Pred(FTitleLines) then { Не надо копировать больше, чем может вместить заголовок } Break; end; until CurPos=0; Result := J+1; end; var DataCol, I, TitleParts : Integer; TextRect : TRect; LineHeight : Integer; begin if (dgTitles in Options) AND (gdFixed in State) AND (ARow = 0) AND (ACol <> 0) then begin { Должна быть нарисована ячейка заголовка } { Стандартное действие DBGrid } if csLoading in ComponentState then begin Canvas.Brush.Color := Color; Canvas.FillRect(ARect); Exit; end; DataCol := ACol; if dgIndicator in Options then Dec(DataCol); { Изменение размеров области заголовка под окантовку, если хочется сделать плоские заголовки, то InflateRect надо пропустить } if [dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines] then InflateRect(ARect, -1, -1); TitleText := Columns[DataCol].Title.Caption; Canvas.Brush.Color := FixedColor; { Если захочется сделать прозрачный заголовок, то вызов FillRect надо будет пропустить } { Если будет желание рисовать фоновую картинку в области заголовка, то нарисовать ее можно здесь } Canvas.FillRect(ARect); { Теперь можно нарисовать собственно текст } Canvas.Font := Font; if FTitleLines = 1 then begin WriteText (Canvas, ARect, 1, 1, TitleText, Columns[DataCol].Title.Alignment); end else begin TitleParts := SplitTitle(); TextRect := ARect; LineHeight := RectHeight(ARect) DIV TitleParts; TextRect.Bottom := TextRect.Top + LineHeight; for I:=0 to Pred(TitleParts) do begin WriteText (Canvas, TextRect, 1, 0, Titles[I], Columns[DataCol].Title.Alignment); OffsetRect(TextRect, 0, LineHeight); end; end; { Окантовка ячейки заголовка, если хочется сделать плоские заголовки, то DrawEdge надо пропустить } if [dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines] then begin InflateRect(ARect, 1, 1); DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT); DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT); end; DoDrawTitleCell (DataCol, Columns[DataCol], ARect); end else inherited; end; |
Кроме того, появляется возможность вызывать пользовательское событие при рисовании области заголовков, причем после того, как заголовок уже нарисован самим компонентом.
Задание высоты заголовков в наследнике также выполняется проще, так как имеется доступ к защищенным свойствам родительского компонента.
procedure THSDBGrid.CalcTitleHeight; begin if dgTitles in Options then RowHeights[0] := (Canvas.TextHeight('gW') + 2) * FTitleLines; end; |
Высоту области заголовка необходимо задавать один раз при создании окна грида и каждый раз, при изменении свойств грида, влияющих на его внешний вид. При создании окна и при изменении свойств грида вызываются виртуальные методы CreateWnd и LayoutChanged, в перекрытые версии которых добавлен вызов процедуры CalcTitleHeight.