Delphi DBGrid 中计算的百分比

Posted

技术标签:

【中文标题】Delphi DBGrid 中计算的百分比【英文标题】:Calculated percentage in Delphi DBGrid 【发布时间】:2018-01-18 10:44:11 【问题描述】:

几天以来,我一直在维护一个 Delphi 应用程序。 客户想要将百分比列添加到 DBGrid,现在显示“数量”列。当然百分比是 行数/总数 * 100

我无法修改基础 TADOTable,因为它在代码的其他地方使用,但我尝试将计算字段添加到 TADOTable - 但似乎计算字段不能具有基于聚合值的值(即数量的总和)。

我成功地在 DBGrid 中添加了一个空列,但是有没有办法在每一行中填充 % 值?

【问题讨论】:

您使用的是什么数据库类型(MS Sql Server、mysql 等)? 我正在使用 MS Access。不,不幸的是没有存储过程可能...... 我正在考虑从数据绑定网格切换到无数据绑定网格,因为它仅用于数据可视化 - 无需编辑 仅供参考,我最终使用了另一个网格组件(来自 LMD Innovative 的 TLMDGrid),它不需要底层数据集,并且每个单元格内容都可以使用语法 thisGrid.Cells[col, row] := 价值; 【参考方案1】:

你想做的事情很简单,但你需要小心你如何做。

暂时将 gui 方面放在一边,您要做的是添加一个经过计算的 列到您的 TAdoDataSet 并在其OnCalcFields 事件中对其进行初始化。然而, 您不要想要做的是在该事件中计算TotalQuantity。 因为 a) 将为数据集中的每一行调用 OnCalcFields 事件 并且 b) 在 OnCalcFields 事件中做任何事情来移动数据集的光标 - 就像在另一个答案中建议的那样遍历数据集 - 将递归 调用OnCalcFields 事件。

避免这种递归问题并避免做不必要的工作的方法是仅在以下情况下计算 TotalQuantity 表第一次打开,任何时候它的值都可以改变,也就是说,当一行 被编辑、插入或删除,然后将结果保存在表单的字段中 或数据模块。您可以通过两种主要方式进行此计算:1)使用 TAdoQuery 使用第二个实例执行像“SELECT SUM(Quantity) FROM MyTable”或 2) 这样的 Sql TAdoDataSet 在您的表上打开。最好第二个实例不应该有任何 gui 与之相连的控件,因此可以在没有 必须使用DisableControlsEnableControls

要将百分比字段添加到您的 AdoDataSet,双击它以弹出字段编辑器,右键单击它并选择 New field。确保将其 Type 设置为 Calculated

一旦您设置了GetTotalQuantity 过程,您需要设置事件处理程序来调用它 来自 AdoDataSet 的 BeforeOpen、BeforeInsert、BeforeEdit 和 AfterDelete 事件。

然后在您的OnCalcFields 事件中,计算并分配您的百分比计算值 给它。

完成这一切所需的代码非常简单,比如

procedure TForm1.GetTotalQuantity;
begin
  //  AdoQuery1 contains Sql to obtain the sum of the AdoDataSet's
  if AdoQuery1.Active then
    AdoQuery1.Close;
  AdoQuery1.Open;
  try
    TotalQuantity := AdoQuery1.Fields[0].AsFloat;  //  TotalQuantity is a field of your for, (or datamodule)
  finally
    AdoQuery1.Close;
  end;
end;

或者

procedure TForm1.GetTotalQuantity;
begin
  //  Note: AdoDataSet2 is a second instance of TAdoDataSet set up to access the same
  //  db table as the one connected to the OP's DBGrid
  if AdoDataSet2.Active then
    AdoDataSet2.Close;
  AdoDataSet2.Open;
  try
    TotalQuantity := 0;
    while not AdoDataSet2.Eof do begin
      TotalQuantity :=  TotalQuantity + AdoDataSet2Quantity.AsFloat; // AdoDataSet2.Quantity.AsFloat;
      AdoDataSet2.Next;
    end;
  finally
    AdoDataSet2.Close;
  end;
end;

OnCalcFields 事件:

procedure TForm1.AdoDataSet1CalcFields(DataSet : TDataSet);
begin
  if TotalQuantity > 0 then
    AdoDataSet1Percentage.AsFloat := AdoDataSet1Quantity.AsFloat / Total Quantity * 100;
end;

将百分比计算字段添加到 AdoDataSet 并为数据集设置 OnCalcFields 事件后,您的 DBGrid 将很乐意显示它,就像数据集的任何其他字段一样。

【讨论】:

糟糕!我对 GetTotalQuantity 的第二个版本做了一个小修正。 我注意到您撤回了对我的回答的接受和赞成。你遇到过问题吗?【参考方案2】:

您是否尝试过在 OnCalcFields 事件中计算百分比?不能 100% 确定以下内容,但此示例可能会对您有所帮助:

procedure TClass.DataSetCalcFields(DataSet: TDataSet);
var
  Bookmark: String;
  TotalQuantity: Double;
begin
    // Save current position
    Bookmark := Dataset.Bookmark;

    // Calculate the total quantity in a while loop through the dataset:
    Dataset.First;
    while not Dataset.Eof do
    begin
      TotalQuantity := TotalQuantity + Dataset.FieldByName('QUANTITY').AsFloat;
      Dataset.Next;
    end;

    // Load current position
    Dataset.Bookmark := Bookmark;

    // Calculate the percentage:
    if TotalQuantity > 0 then
    begin
      Dataset.FieldByName('PERCENTAGE').AsFloat := Dataset.FieldByName('QUANTITY').AsFloat / TotalQuantity * 100;
    end
    else
    begin
      Dataset.FieldByName('PERCENTAGE').AsFloat := 0;
    end;
  end;
end;

【讨论】:

另外,您是否考虑过这种方式对性能的影响? @MartynA 是的,这肯定是一个问题,但这只是我想到的最快的解决方案.. 肯定有更好的方法来获得总量。我只是想向 OP 展示 OnCalcFields 事件的示例。

以上是关于Delphi DBGrid 中计算的百分比的主要内容,如果未能解决你的问题,请参考以下文章

delphi 中的DBGRID列之间自动计算如何写程序

在 Delphi 中获取自定义 DPI 百分比

delphi sql查询结果小于1,转换成百分比后不显示小数点前面的0,比如0.1%,显示结果就是.1%.

Delphi里ProgressBar在更新进度的时候,能够显现百分比吗?

delphi dbgrid

delphi中如何在dbgrid中主动添加序号?求赞助!