Delphi 网格:如何获取所选行数 "on the fly"

Delphi Grid: How to get selectedrows count "on the fly"

使用 SelectedRows.Count 我可以计算所选网格行的数量。例如,如果用户选择了 3 行,我可以在表单上放置一个按钮并单击它可以显示所选的数字。很好。

但是我怎样才能在用户选择它们时更新行数 ("on the fly")。我尝试了很多 Grid 事件,例如 OnColEnterOnMouseDown。他们似乎只在用户点击数据列外时才更新计数,而不是在第一次选择一行时。

Grid 组件中没有看到与更改 ROWS 相关的事件,我在底层数据查询中尝试了很多事件,但它们也不一致或经常需要在某些地方单击。我找到的最佳结果(实际代码)是在滚动查询之后:

procedure TDataHerd10.QuCowsAfterScroll(DataSet: TDataSet);
begin
  if MenuOpt = 'UpdtInd' then MainView.NumSelEdit.Text:=
    IntToStr(MainView.CowSelGrid.SelectedRows.Count);
end;

这个事件似乎落后了一个,当用户放弃多选返回到单行时,最初的计数又增加了一个。

似乎有了正确的事件,我应该能够计算选定的行以向用户报告,因为它们 select/unselect 行?

更新: 我发现修改原始文件比我预期的要棘手 回答以可靠地满足您显示 select 计数的要求 当表单首次显示时。

以下是我希望可靠运行的测试平台项目的要点 正如你所要求的。除了 DBGrid,表单还有一个 TEdit,我使用它 确保 dbgrid 最初没有聚焦(以便更容易观察 dbgrid 的行为)和 3 个 TButtons 函数应该是来自它们的 OnClick 处理程序的 self-evident。

你会注意到捕捉变化计数的代码 dbgrid 的 selection 计数仅在 dbgrid 的 OnDrawColumnCell 中触发 事件。然而,这被调用得太频繁了(在我的例子中超过 700 首次显示表单之前的时间)正在做其他事情 每次触发时都在 gui 中。所以相反,表单有一个变量 它跟踪 selection 计数并只更新它的显示 当计数发生变化时(在 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;

原回答如下

我通常使用 DataSet.AfterScroll 来做 non-gui 需要与其当前行同步的事情。不幸的是,正如您显然发现的那样,它在 DBGrid 上效果不佳,尤其是因为可以在不滚动数据集的情况下更改网格中当前行的 selection 状态(例如,通过单击它)。

不幸的是,

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
  Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;

也不能完全完成工作,原因很明显,您可以在不使用鼠标的情况下从当前行扩展 selection - 例如Shift + Down 也可以。

但是,如果您只添加

procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift:
    TShiftState);
begin
  Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;

它使用键盘来更改 selection(s) 并且到目前为止拒绝了我 wrong-foot 它的尝试。如果您允许用户在网格中进行 in-place 编辑,您可能需要过滤用于更新 select 离子计数显示的 Key 值。

顺便说一句,考虑到键盘皱纹以及 AfterScroll 的问题,您的 q 似乎不值得(无论如何对我来说)它得到的反对票,所以我给了它 +1。

为@Martyn 的出色回答添加更多内容...

为了自动更新显示的计数 ("on the fly"),我发现使用 Grid1.KeyUp 更新计数的建议非常好,而且还添加了其他几个事件的计数更新.最关键的是 Grid1.MouseUp。否则,用户可以单击当前选定行之外的新行并丢失所有行选择,但显示的计数将保持不变而不是返回零。