Getting Data for Custom Report Component

Mark ElderMark Elder SD, USA
edited 7:16AM in FastReport VCL 5
I'm trying to build a custom Report Component

My component will add an IndentLevelFieldName and IndentWidth property to the standard View. This will add an indent before printing the field based on the "level" set in a different DataSet field. I'm going to use this to print tree structures in a report.

I can register the component, add it to a report, and see my new properties. However I can't seem to get the correct values by the time I'm in the draw event. I have overridden the GetData event, but I still always have a zero for the FIndentLevel when I get into the draw code.

How do I setup my component state so that the Draw method as the correct values?

Here is the code for my component:
unit MgrFastReportComponents;

interface

uses
  // Delphi
  System.Types,
  Classes, Graphics,

  // FastReport
  frxClass, frxDesgnEditors;
type


  TMgrIndentMemoView = class(TFrxMemoView)
    private
      FIndentWidth: integer;
      FIndentLevelFieldName: string;
      FIndentLevel: integer;
    public
      procedure Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX, OffsetY: Extended); override;
    published
      property IndentWidth: integer read FIndentWidth write FIndentWidth;
      property IndentLevelFieldName: string read FIndentLevelFieldName write FIndentLevelFieldName;
      property IndentLevel: integer read FIndentLevel write FIndentLevel;

      procedure GetData; override;
  end;

implementation

uses
  System.UITypes,
  StrUtils,
  SysUtils,
  frxDsgnIntf,
  frxUtils,
  frxRes,
  Winapi.Windows;


type
  TfrxDataFieldProperty = class(TfrxPropertyEditor)
  public
    function GetValue: String; override;
    function GetAttributes: TfrxPropertyAttributes; override;
    procedure GetValues; override;
    procedure SetValue(const Value: String); override;
  end;

{ TfrxDataFieldProperty }

function TfrxDataFieldProperty.GetAttributes: TfrxPropertyAttributes;
begin
  Result := [paMultiSelect, paValueList];
end;

function TfrxDataFieldProperty.GetValue: String;
begin
  Result := GetStrValue;
end;

procedure TfrxDataFieldProperty.SetValue(const Value: String);
begin
  SetStrValue(Value);
  if Component is TfrxCustomMemoView then
    with TfrxCustomMemoView(Component) do
      if IsDataField then
        Text := '[' + DataSet.UserName + '."' + DataField + '"]';
end;

procedure TfrxDataFieldProperty.GetValues;
var
  ds: TfrxDataSet;
begin
  inherited;
  ds := TfrxView(Component).DataSet;
  if ds <> nil then
    ds.GetFieldList(Values);
end;




var
  Bmp_IndentMemo: Graphics.TBitmap;

{ TMgrIndentMemoView }

procedure TMgrIndentMemoView.Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX,
  OffsetY: Extended);
begin


  if IsDesigning = true then
    inherited
  else
  begin
    inherited Draw(Canvas, ScaleX, ScaleY, OffsetX + (FIndentLevel * FIndentWidth), OffsetY);
  end;

end;

procedure TMgrIndentMemoView.GetData;
begin
  FIndentLevel := 0;

  if DataSet <> nil then
  begin
    try
      FIndentLevel := DataSet.Value[FIndentLevelFieldName];
    except on E: Exception do
      begin
        // can I log the exception anywhere?? Where do our "info" errors
        // get logged?
        FIndentLevel := 0;
      end;
    end;
  end;

  inherited;
end;

initialization
  Bmp_IndentMemo := Graphics.TBitmap.Create;
  //Bmp_FormProp.LoadFromResourceName(hInstance, 'CF_PAGE_PROPERTIES');
  frxObjects.RegisterObject(TMgrIndentMemoView, Bmp_IndentMemo);

  frxPropertyEditors.Register(TypeInfo(String), TfrxView, 'IndentLevelFieldName', TfrxDataFieldProperty);

finalization
  FreeAndNil(Bmp_IndentMemo);

end.

Comments

  • gpigpi
    edited 7:16AM
    You should override Diff function for TfrxMemoView
    unit MgrFastReportComponents;
    
    interface
    
    uses
    // Delphi
    System.Types,
    Classes, Graphics,
    // FastReport
    frxClass, frxDesgnEditors;
    type
    
    TMgrIndentMemoView = class(TfrxMemoView)
    private
      FIndentWidth: integer;
      FIndentLevelFieldName: string;
      FIndentLevel: integer;
    public
      procedure Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX, OffsetY: Extended); override;
      function Diff(AComponent: TfrxComponent): String; override;
    published
      property IndentWidth: integer read FIndentWidth write FIndentWidth;
      property IndentLevelFieldName: string read FIndentLevelFieldName write FIndentLevelFieldName;
      property IndentLevel: integer read FIndentLevel write FIndentLevel;
      procedure GetData; override;
    
    end;
    
    implementation
    
    uses
    System.UITypes,
    StrUtils,
    SysUtils,
    frxDsgnIntf,
    frxUtils,
    frxRes,
    frxXML,
    Winapi.Windows;
    
    type
    TfrxDataFieldProperty = class(TfrxPropertyEditor)
    public
    function GetValue: String; override;
    function GetAttributes: TfrxPropertyAttributes; override;
    procedure GetValues; override;
    procedure SetValue(const Value: String); override;
    end;
    
    { TfrxDataFieldProperty }
    
    function TfrxDataFieldProperty.GetAttributes: TfrxPropertyAttributes;
    begin
    Result := [paMultiSelect, paValueList];
    end;
    
    function TfrxDataFieldProperty.GetValue: String;
    begin
    Result := GetStrValue;
    end;
    
    procedure TfrxDataFieldProperty.SetValue(const Value: String);
    begin
    SetStrValue(Value);
    if Component is TfrxCustomMemoView then
    with TfrxCustomMemoView(Component) do
    if IsDataField then
    Text := '[' + DataSet.UserName + '."' + DataField + '"]';
    end;
    
    procedure TfrxDataFieldProperty.GetValues;
    var
    ds: TfrxDataSet;
    begin
    inherited;
    ds := TfrxView(Component).DataSet;
    if ds <> nil then
    ds.GetFieldList(Values);
    end;
    
    var
    Bmp_IndentMemo: Graphics.TBitmap;
    
    { TMgrIndentMemoView }
    
    procedure TMgrIndentMemoView.Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX,
    OffsetY: Extended);
    begin
    if IsDesigning = true then
    inherited
    else
    begin
    inherited Draw(Canvas, ScaleX, ScaleY, OffsetX + (FIndentLevel * FIndentWidth), OffsetY);
    end;
    
    end;
    
    procedure TMgrIndentMemoView.GetData;
    begin
    inherited;
    FIndentLevel := 0;
    if DataSet <> nil then
    begin
    try
    FIndentLevel := DataSet.Value[FIndentLevelFieldName];
    except on E: Exception do
    begin
    // can I log the exception anywhere?? Where do our "info" errors
    // get logged?
    FIndentLevel := 0;
    end;
    end;
    end;
    
    end;
    
    function TMgrIndentMemoView.Diff(AComponent: TfrxComponent): String;
    var
      m: TMgrIndentMemoView;
      s: WideString;
      c: Integer;
    begin
      Result := inherited Diff(AComponent);
      m := TMgrIndentMemoView(AComponent);
    
      if FIndentWidth <> m.FIndentWidth then
        Result := Result + ' IndentWidth="' + IntToStr(FIndentWidth) + '"';
      if FIndentLevel <> m.FIndentLevel then
        Result := Result + ' IndentLevel="' + IntToStr(FIndentLevel) + '"';
      if FIndentLevelFieldName <> m.FIndentLevelFieldName then
        Result := Result + ' IndentLevelFieldName="' + frxStrToXML(FIndentLevelFieldName) + '"';
    end;
    
    
    initialization
    Bmp_IndentMemo := Graphics.TBitmap.Create;
    //Bmp_FormProp.LoadFromResourceName(hInstance, 'CF_PAGE_PROPERTIES');
    frxObjects.RegisterObject(TMgrIndentMemoView, Bmp_IndentMemo);
    
    frxPropertyEditors.Register(TypeInfo(String), TfrxView, 'IndentLevelFieldName', TfrxDataFieldProperty);
    
    finalization
    FreeAndNil(Bmp_IndentMemo);
    
    end.
    

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.