Using SelectedRows.Count
I can get a count of the number of grid rows selected. For example, if the user selected 3 rows, I can put a button on the form and clicking that can show me the number selected. Fine.
BUT how could I update the number of rows as the user selects them ("on the fly"). I have tried many of the Grid
events, like OnColEnter
or OnMouseDown
. They seem to update the count only when the user clicks just outside the data columns, and not when a row is first selected.
Not seeing events related to changing ROWS in the Grid
component, I tried many events in the underlying data query, but they too were inconsistent or often required clicking in certain places. The best result I found (actual code) was after scrolling the query:
procedure TDataHerd10.QuCowsAfterScroll(DataSet: TDataSet);
begin
if MenuOpt = 'UpdtInd' then MainView.NumSelEdit.Text:=
IntToStr(MainView.CowSelGrid.SelectedRows.Count);
end;
This event seems to lag one behind, and adds one more to the count initially when the user abandons the multiselect to go back to a single row.
Seems like with the right event, I should be able to count the selected rows to report to the user as they select/unselect rows?
Update: I found it trickier than I was expecting to modify my original answer to reliably meet your requirement to have the select count displayed when the form first shows.
Below are the essentials of the testbed project which I hope reliably behaves as you asked for. In addition to the DBGrid, the form has a TEdit, which I use to ensure that the dbgrid is not initially focused (so as to make it easier to observe the dbgrid's behaviour) and 3 TButtons whose functions should be self-evident from their OnClick handlers.
You'll notice that the code that catches the changing count of the dbgrid's selection count is only triggered in the dbgrid's OnDrawColumnCell event. However, this is called rather too frequently (in my case over 700 times before the form is first displayed) to be doing something else in the gui every time it is triggered. So instead, the form has a variable which keeps track of the selection count and only updates the display of it when the count changes (in the SetSelectedCount setter).
type
TForm1 = class(TForm)
[...]
private
FSelectedCount: Integer;
procedure SetSelectedCount(const Value: Integer);
public
procedure ShowSelectedCount;
property SelectedCount : Integer read FSelectedCount write SetSelectedCount;
end;
[...]
procedure TForm1.btnClearSelectedClick(Sender: TObject);
begin
DBGrid1.SelectedRows.Clear;
end;
procedure TForm1.btnGetSelectedClick(Sender: TObject);
begin
ShowSelectedCount;
end;
procedure TForm1.btnSetSelectedClick(Sender: TObject);
begin
DBGrid1.SelectedRows.CurrentRowSelected := True;
end;
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
SelectedCount := DBGrid1.SelectedRows.Count;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ActiveControl := Edit1; // so the grid does not have focus when the form is first shown
SelectedCount := -1;
end;
procedure TForm1.SetSelectedCount(const Value: Integer);
begin
if FSelectedCount <> Value then begin
FSelectedCount := Value;
ShowSelectedCount;
end;
end;
procedure TForm1.ShowSelectedCount;
begin
Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;
Original answer follows
I usually use DataSet.AfterScroll
for doing non-gui things which need to be synchronised with its current row. Unfortunately, it doesn't work so well with a DBGrid, as you've obviously found, not least because the current row's selection state in the grid can be changed (e.g. by clicking it) without the dataset scrolling.
Unfortunately,
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;
doesn't quite do the job, either, for the fairly obvious reason that you can extend a selection from the current row without using the mouse - e.g. Shift + Down will do it, too.
However, if you just add
procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;
that takes use of the keyboard to change the selection(s) into account and has so far resisted my attempts to wrong-foot it. If you are allowing the user to do in-place editing in the grid, you might want to filter the Key
values which are used to update your display of the selection count.
Btw, taking the keyboard wrinkleas well as the problem with AfterScroll into account, your q doesn't seem to deserve (to me at any rate) the downvote it's got , so I've given it a +1.