You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TFDQuery子类中拦截设计时添加持久化字段的操作?

拦截TFDQuery设计时字段添加并自动美化DisplayLabel

请问是否有办法拦截TFDQuery子类中字段的添加操作?我已实现BeautifyDisplayLabels方法,可将FieldName(如factoryLine5)转换为更符合阅读习惯的DisplayLabel(如Factory Line 5)。现在我希望在设计时每次向Query添加新的持久化字段时,能自动调用该方法,而非手动触发。请问应该重写哪个方法来拦截设计时字段的添加操作?

要在设计时自动美化新增字段的DisplayLabel,你需要重写TFDQuery继承链中的两个关键方法,覆盖不同场景:

  • 重写CreateField方法:拦截单个字段的创建过程,在字段生成后立即美化其DisplayLabel
  • 重写DoFieldsChange方法:处理批量添加字段(如通过字段编辑器一次性导入)的场景,触发全量字段的美化

以下是修改后的完整代码:

unit MyQuery;

interface

uses System.Classes, FireDAC.Comp.Client;

type TKpQuery = class(TFDQuery)
  private
    function BeautifyFieldName(FieldName: string): string;
  protected
    function CreateField(FieldClass: TFieldClass; const FieldName: string; AFieldKind: TFieldKind): TField; override;
    procedure DoFieldsChange; override;
  public
    procedure BeautifyDisplayLabels;
  published
end;

procedure Register;

implementation

uses
  Data.DB,
  System.Types,
  System.SysUtils,
  System.StrUtils,
  System.RegularExpressions;

procedure Register;
begin
  {$IFDEF WIN32}
  RegisterComponents('My Data Access', [TKpQuery]);
  {$ENDIF}
end;

function TKpQuery.CreateField(FieldClass: TFieldClass; const FieldName: string; AFieldKind: TFieldKind): TField;
begin
  Result := inherited CreateField(FieldClass, FieldName, AFieldKind);
  // 仅在设计时处理,避免干扰运行时逻辑
  if (Result <> nil) and (csDesigning in ComponentState) then
  begin
    if (Result.DisplayLabel.Trim = '') or (Result.DisplayLabel = Result.FieldName) then
      Result.DisplayLabel := BeautifyFieldName(Result.FieldName);
  end;
end;

procedure TKpQuery.DoFieldsChange;
begin
  inherited;
  // 设计时字段集合批量变更后,统一美化未自定义的DisplayLabel
  if csDesigning in ComponentState then
    BeautifyDisplayLabels;
end;
   
procedure TKpQuery.BeautifyDisplayLabels;
var i: integer;
begin
  for i := 0 to Fields.Count - 1 do
  begin
    if (Fields[i].DisplayLabel.Trim = '') or (Fields[i].DisplayLabel = Fields[i].FieldName) then
      Fields[i].DisplayLabel := BeautifyFieldName(Fields[i].FieldName);
  end;
end;

function TKpQuery.BeautifyFieldName(FieldName: string): string;
var
  Words: TStringDynArray;
  i: integer;
begin
  FieldName := TRegEx.Replace(FieldName, '([a-z])([A-Z])', '$1 $2'); // factoryLine -> factory Line
  FieldName := TRegEx.Replace(FieldName, '([a-z]|[A-Z])(\d)', '$1 $2'); // Line123 -> Line 123
  FieldName := TRegEx.Replace(FieldName, '(\d)([a-z]|[A-Z])', '$1 $2'); // 1428ElmStreet -> 1428 ElmStreet

  Words := FieldName.Split([' ', '.', '_']);
  for i := 0 to Length(Words) - 1 do
    Words[i] := UpperCase(Words[i][1]) + Copy(Words[i], 2, 999);

  Result := String.Join(' ', Words);
end;

end.

关键逻辑说明

  • CreateField是TDataSet的虚方法,每次在设计器中创建单个持久化字段时都会被调用,继承实现后添加美化逻辑,确保单个字段创建后立即生效。
  • DoFieldsChange会在字段集合发生批量变更时触发(比如通过字段编辑器一次性添加多个字段),此时调用已有的BeautifyDisplayLabels方法,批量处理所有未自定义DisplayLabel的字段。
  • 加入csDesigning in ComponentState判断,确保美化逻辑仅在设计时执行,不会影响运行时的字段行为。

内容的提问来源于stack exchange,提问作者Marc Guillot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 12:31:08