Delphi:如何查找和格式化DBGrid字段

时间:2013-06-26 18:10:38

标签: delphi delphi-xe2 dbgrid

我使用DBGrid和Delphi XE2来显示一些查询结果。 在结果中,一些(整数)字段表示我想以某种格式显示的持续时间(以秒为单位),例如“hh:mm:ss” 我事先并不知道字段顺序,因为查询可能不同但我知道要格式化的字段名称。 最有效的方法是什么?

2 个答案:

答案 0 :(得分:3)

虽然@AndreaBoc的答案是正确的(但只回答了你的一个问题),但它有些重复:复制粘贴相同的计算看起来对我来说是一种反模式。

使用http://docwiki.embarcadero.com/Libraries/XE4/en/System.Math.DivMod

可能会删除重复性
procedure TForm1.PrettyPrintSeconds(Sender: TField;
  var Text: string; DisplayText: Boolean);
var
  hh,mm,ss: Word;
begin
  DivMod( Sender.AsInteger, 3600, hh, mm );
  DivMod( mm, 60, mm, ss );
  Text := Format('%.2d:%.2d:%.2d',[hh,mm,ss]);
end;

此外,如果你真的想要高效(但为什么要使用TDataset?)你可以用3个临时字符串变量和旧式{替换太灵活的格式函数{1}} http://docwiki.embarcadero.com/Libraries/XE4/en/System.SysUtils.IntToStr概述的程序: - )

应为http://docwiki.embarcadero.com/Libraries/XE2/en/Data.DB.TField.OnGetText

设置

这比复制粘贴相同的操作要好两倍甚至更多,增加了CPU时间和制造愚蠢错字的机会。

然后还有下一部分问题:不知道字段顺序...但我知道要格式化的字段名称。这意味着您应该在查询打开后调整此字段:

Str

procedure TDataModule1.Query1AfterOpen(DataSet: TDataSet); var F: TField; begin F := DataSet.FindField('MY-Name-For-Time'); if F = nil then (* .... no such field - do something about it .... *) else F.OnGetText := TForm1.PrettyPrintSeconds; end; 事件中,您可以类似地删除(设置为BeforeClose)此事件处理程序。只是为了那个罕见的检查,以后相同的TField对象被重新用于不同的目的。除了一些非常奇特的情况,它不应该发生,而只是为了“自我清理”。


效果较差(从CPU的角度来看),但精神方法中的VCL也更多。

对于nil事件中的查询:查找上面给定的字段名称,如果找到则:

  1. 保存结果供以后使用(因为AfterOpen内的线性字符串搜索本身并不是最有效的操作,所以不应该为每个显示的值重复它)
    • 适当但有点乏味的方法是为查询所有者创建新的FieldByName属性。
    • 在Win32下你可以(ab)使用TTimeField属性Int32,通过type-cast存储指针。这是脆弱,不安全和不可移植的代码,但在任何这些变量中存储TDataSet.TagIntegerpointer值都是“旧的Delphi样式”(就像在TStringList.Objects中一样) )如果你小心并且只对Win32感兴趣,它就可以工作。
  2. 添加日期时间类型的计算字段
  3. TObject设置为该新字段的格式:http://docwiki.embarcadero.com/Libraries/XE2/en/Data.DB.TDateTimeField.DisplayFormat
  4. 使新字段对DBGrid和其他支持db的控件友好
  5. 使原始字段不可见或从网格中删除其列 - 您将改为使用新字段。
  6. 然后在查询上设置'hh:nn:ss',如:

    OnCalcFields

    然后,您就可以在Delphi例程期望// 1. Delphi TDateTime is double and 1 day equals to 1.0 // 2. Multiplication is more efficient than division - do it by pen and paper and see procedure TDataModule1.Query1AfterOpen(DataSet: TDataSet); const coeff = 1.0 / ( 24 * 60 * 60 ); begin MyCalcField.AsTime := MySourceField.AsInteger * coeff; end; 值的每个地方使用新的虚拟字段。

答案 1 :(得分:1)

您可以使用该字段的OnGetText事件请求:

procedure TForm1.Table1secondsGetText(Sender: TField;
  var Text: string; DisplayText: Boolean);
var
  seconds,hh,mm,ss:Integer;
begin
  seconds := Sender.AsInteger;
  hh := seconds div 3600;
  mm := (seconds - (hh * 3600)) div 60;
  ss := (seconds - (hh * 3600) - (mm * 60));
  Text := Format('%.2d:%.2d:%.2d',[hh,mm,ss]);
end;

例如185秒将以这种方式显示:00:03:05