How to Custom Paint Table Views
- 4 minutes to read
Custom painting allows much deeper appearance customization compared to the capabilities provided by the Spreadsheet and Report Designer controls’ API. Handle a OnCustomDraw~ event corresponding to a specific worksheet area or visual element(s) to custom paint a Table View worksheet:
OnCustomDrawTableViewCell allows you to perform custom drawing on worksheet cells;
OnCustomDrawTableViewCommonCell allows you to custom draw the frozen pane separators and other helper table elements;
OnCustomDrawTableViewHeaderCell allows you to custom paint the cells within the column and row headers.
Custom painting can be useful for expanding the control with custom functionality. For example, you want to show formula calculation error hints to provide an end-user with more informative notifications than the standard error codes displayed within the formula cell. The example below illustrates how you can implement custom paint tasks in these cases.
First, implement the callout painting procedure that displays an error code hint:
procedure DrawCallout(ACanvas: TcxCanvas; AViewInfo: TdxSpreadSheetTableViewCellViewInfo; AError: TdxSpreadSheetFormulaErrorCode);
var
AClipRgn, AFrameRgn: TcxRegion;
FramePoints: array[0..5] of TPoint;
AMessage: UnicodeString;
AHOffset: Integer;
begin
case AError of // Pick an appropriate callout message according to the formula error code
ecNull:
begin
AMessage := 'Place separators between specified cell ranges';
AHOffset := 320;
end;
ecDivByZero:
begin
AMessage := 'Division by zero: check formula arguments';
AHOffset := 300;
end;
ecValue:
begin
AMessage := 'Wrong types of arguments';
AHOffset := 200;
end;
ecRefErr:
begin
AMessage := 'Invalid cell reference';
AHOffset := 200;
end;
ecName:
begin
AMessage := 'Formula is not recognized';
AHOffset := 200;
end;
ecNUM:
begin
AMessage := 'Invalid numeric argument';
AHOffset := 200;
end;
ecNA:
begin
AMessage := 'Result is not found';
AHOffset := 180;
end
else
begin
AMessage := 'OK';
AHOffset := 50;
end;
end;
ATopLeft.x = AViewInfo->DisplayBounds.left;
ATopLeft.y = AViewInfo->DisplayBounds.top;
FramePoints[0] := cxPointOffset(ATopLeft, 0, 10);
FramePoints[1] := cxPointOffset(FramePoints[0], 5, -10);
FramePoints[2] := cxPointOffset(FramePoints[1], AHOffset, 0);
FramePoints[3] := cxPointOffset(FramePoints[2], 0, -20);
FramePoints[4] := cxPointOffset(FramePoints[3], -AHOffset, 0);
FramePoints[5] := FramePoints[0];
AFrameRgn := TcxRegion.Create;
AFrameRgn.Handle := CreatePolygonRgn(FramePoints, Length(FramePoints), WINDING);
ACanvas.SaveState;
AClipRgn := TcxRegion.Create(AViewInfo.ViewInfo.CellsArea);
AClipRgn.Combine(AFrameRgn, roIntersect, False);
ACanvas.SetClipRegion(AClipRgn, roSet, False);
FillRegionByColor(ACanvas.Handle, AFrameRgn.Handle, clInfoBk);
FrameRgn(ACanvas.Handle, AFrameRgn.Handle, GetStockObject(BLACK_BRUSH), 1, 1);
ACanvas.Font.Name := 'Tahoma';
ACanvas.Font.Size := 10;
ACanvas.Font.Color := clBlack;
ACanvas.Font.Style := [fsBold];
ACanvas.Brush.Style := bsClear;
ACanvas.DrawTexT(AMessage, cxRect(FramePoints[4], FramePoints[2]),
cxAlignVCenter or cxAlignHCenter or cxSingleLine);
ACanvas.RestoreState;
ACanvas.SetClipRegion(AClipRgn, roSubtract);
AFrameRgn.Free;
end;
Then, call the DrawCallout procedure within the OnCustomDrawTableViewCell event handler:
procedure SpreadSheetCustomDrawTableViewCell(Sender: TdxSpreadSheetTableView; ACanvas: TcxCanvas; AViewInfo: TdxSpreadSheetTableViewCellViewInfo; var AHandled: Boolean);
var
AErrorCode: TdxSpreadSheetFormulaErrorCode;
begin
if (AViewInfo.Cell = nil) or (AViewInfo.Cell.DataType <> cdtFormula) then Exit;
AErrorCode := AViewInfo.Cell.AsFormula.ErrorCode;
if (AViewInfo.Cell.AsFormula.ErrorCode <> ecNone) or
(not VarIsNumeric(AViewInfo.Cell.AsFormula.Value) or (AViewInfo.Cell.AsFormula.Value < 0)) then
begin
ACanvas.Brush.Color := clRed;
ACanvas.Font.Color := clAqua;
DrawCallout(ACanvas, AViewInfo, AErrorCode);
end;
end;
As a result, the Spreadsheet/Report Designer control displays formula error hints in callout boxes. The image below shows the division by zero error hint: