几天以来,我一直在维护一个 Delphi 应用程序。客户想要将百分比列添加到 DBGrid,现在显示“数量”列。当然百分比是行数量/总数量 * 100
我无法修改基础 TADOTable,因为它在代码的其他地方使用,但我尝试将计算字段添加到 TADOTable - 但似乎计算字段不能具有基于聚合值(即数量总和)的值。
我成功地向 DBGrid 添加了一个空列,但是有什么方法可以填充每行中的 % 值吗?
您想要做的事情很简单,但是您需要小心如何做。
暂时将 gui 方面放在一边,您要做的是将计算列添加到您的 TAdoDataSet 并在其OnCalcFields
事件中对其进行初始化。但是,您不想做的是在该事件中计算TotalQuantity
。因为a)OnCalcFields
将为数据集中的每一行调用事件,并且b)在OnCalcFields
事件内部执行任何移动数据集光标的操作(例如按照另一个答案中的建议遍历数据集)将递归调用该OnCalcFields
事件。
避免这种递归问题并避免做任何不必要的工作的方法是仅在表第一次打开时计算 TotalQuantity 并且它的值可能随时更改,即当编辑、插入或删除行时,然后将结果保存在表单或数据模块的字段中。有两种主要方法可以进行此计算:1) 使用 TAdoQuery 执行 Sql,如“SELECT SUM(Quantity) FROM MyTable”或 2) 使用
在表上打开的第二个 TAdoDataSet 实例。优选地,第二个实例不应连接任何 gui 控件,因此可以尽快遍历它而无需使用DisableControls
and EnableControls
。
要将百分比字段添加到您的 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 将很乐意显示它,就像数据集的任何其他字段一样。
您是否尝试过在 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;