A bit advanced topic...
For subclassing you simply declare a new class which descends from TStringGrid. In the code of this new class you have access to all protected methods, among them the Paint method. Here you first call the inherited method (which draws the regular grid). Then you determine whether there's any empty space below the last row. If there is you loop through columns and rows, calculate the rectangle bounaries of each cell and call the inherited method for drawing the cell background (DrawFillRect) and grid lines (DrawCellGrid); these methods already take care of selecting the correct pen and brush for each cell.
type
TNewStringGrid = class(TStringGrid)
protected
procedure Paint; override;
end;
procedure TNewStringGrid.Paint;
var
Rct: TRect;
y: Integer;
c, r: Integer;
state: TGridDrawState;
begin
// Call the inherited method, i.e. paint the grid as usual
inherited;
// Measure the rectangle of the last regular row to learn whether there's empty space below it
Rct := CellRect(0, RowCount-1);
y := Rct.Bottom;
if y < ClientHeight then
begin
// Yes, we must draw "dummy" rows...
r := RowCount;
while y < ClientHeight do begin
// Draw column by column
for c := 0 to ColCount - 1 do begin
if c < FixedCols then
state := [gdFixed]
else
state := [];
Rct := CellRect(c, RowCount-1);
Rct.Top := y;
Rct.Bottom := y + DefaultRowHeight;
PrepareCanvas(c, r, state);
DrawFillRect(Canvas, Rct);
DrawCellGrid(c, r, Rct, state);
end;
// Advance to next "dummy" row
inc(y, DefaultRowHeight);
inc(r);
end;
end;
end;
Normally you would have to create this new grid at runtime, or you would have to put it into a package and install it in the IDE to have it on the component palette. But you can even go a step further and name the type of the new grid class like the old one, TStringGrid, and prepend the name of the old grid type by its unit (Grids.TStringGrid).
type
TStringGrid = class(Grids.TStringGrid)
...
When you now put the code into the same unit as the form in which the new grid is used, or when you put the code into a separate unit and list that at the end of the uses clause, you can fool the compiler and the IDE: dropping the grid on the form from the component palette at design-time creates an old TStringGrid (Grids.TStringGrid, to be exact) but at run-time the compiler sees only the code of the new stringgrid and calls the new Paint method.
Have a look at the attached demo project.
I still think that this kind of grid is confusing. For example, you can click into one of the dummy cells, but that is not marked as focused, and you cannot type any text in it... Try to convince your boss that this a very poor GUI.