14
votes

I have a TStringGrid, and I want to delete the selected row. Basic things I've tried only delete the last row. How do I delete an arbitrary row?

2

2 Answers

15
votes

If the code you've tried only deletes the last row, then you're probably just decrementing the RowCount property. That indeed always makes its modifications on the end of the list of rows. With that in mind, you could write code to ensure that the row you no longer want is the one at the end, and then delete the last row. (The most direct way would be to move the row, and there's a MoveRow method, but it's protected. If you wish to call protected methods, though, you may as well just call DeleteRow instead.)

Using only public and published members, it's possible to write a loop that deletes an arbitrary row. For example, here's some code inspired by Scalabium Software's FAQ on this topic:

procedure DeleteRow(Grid: TStringGrid; ARow: Integer);
var
  i: Integer;
begin
  for i := ARow to Grid.RowCount - 2 do
    Grid.Rows[i].Assign(Grid.Rows[i + 1]);
  Grid.RowCount := Grid.RowCount - 1;
end;

It copies the contents of each row below the one you wish to delete into the row above. At the end of the loop, the row you wish to delete has been overwritten (by the row immediately below it) and there are two copies of the final row. Then it simply deletes the final row.

To delete the current row of the grid, call the function like this:

DeleteRow(Grid, Grid.Row);
10
votes

The selected row of the grid is given by its Row property.

TCustomGrid has a DeleteRow method, but it's protected, so you can't call it except from within descendants of that class. It's easy to circumvent that restriction, though. Declare a TCustomGrid descendant, and then type-cast your grid control to that new type. Call DeleteRow on the result.

type
  TCustomGridAccess = class(TCustomGrid) end;

procedure DeleteGridRow(g: TCustomGrid; row: Integer);
begin
  TCustomGridAccess(g).DeleteRow(row);
end;

This works because in Delphi, members with protected visibility are implicitly public within the same unit as the class's declaration. Although TCustomGrid is declared in the Grids unit, our TCustomGridAccess class is declared in your unit, so your unit has access to all its protected methods, including DeleteRow.


If your Delphi version is new enough, then you can use a class helper. Class helpers can access protected members and don't require type-casting to technically unrelated types.

type
  TCustomGridHelper = class helper for TCustomGrid
  public
    procedure DelRow(ARow: Integer);
  end;

procedure TCustomGridHelper.DelRow(ARow: Integer);
begin
  Self.DeleteRow(ARow);
end;

Then, simply use the unit where you've declared the helper. Any descendant of TCustomGrid will automatically have a DelRow method, which you can call just like any other grid method:

grid.DelRow(grid.Row);