如何在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
相关产品推荐
相关产品推荐

