1. 程式人生 > 其它 >FastReport 報表工具如何為屬性建立編輯器

FastReport 報表工具如何為屬性建立編輯器

本文介紹了FastReport VCL如何為屬性建立編輯器。當你在設計器中選擇一個元件時,它的屬性會顯示在物件檢查器中。你可以為任何屬性建立你自己的編輯器。

FastReport VCL是用於 Delphi、C++ Builder、RAD Studio 和 Lazarus 的報告和文件建立 VCL 庫。它提供了視覺化模板設計器,可以訪問 30 多種格式,並可以部署到雲、網站、電子郵件和列印中。

【慧都網】下載FastReport VCL v6.9最新版

當你在設計器中選擇一個元件時,它的屬性會顯示在物件檢查器中。你可以為任何屬性建立你自己的編輯器。"字型 "屬性的標準編輯器可以作為例子:如果這個屬性被選中,在行的右側出現...按鈕;通過點選這個按鈕呼叫標準的 "字型屬性 "對話方塊。還有一個例子是 "顏色 "屬性編輯器。它在下拉列表中顯示標準顏色和顏色規格名稱。

所有屬性編輯器的基類在 "frxDsgnIntf "單元中描述。

  TfrxPropertyEditor = class(TObject)
  protected
    procedure GetStrProc(const s: String);
    function GetFloatValue: Extended;
    function GetOrdValue: Integer;
    function GetStrValue: String;
    function GetVarValue: Variant;
    procedure SetFloatValue(Value: Extended);
    procedure SetOrdValue(Value: Integer);
    procedure SetStrValue(const Value: String);
    procedure SetVarValue(Value: Variant);
  public
    constructor Create(Designer: TfrxCustomDesigner); virtual;
    destructor Destroy; override;
    function Edit: Boolean; virtual;
    function GetAttributes: TfrxPropertyAttributes; virtual;
    function GetExtraLBSize: Integer; virtual;
    function GetValue: String; virtual;
    procedure GetValues; virtual;
    procedure SetValue(const Value: String); virtual;
    procedure OnDrawLBItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); virtual;
    procedure OnDrawItem(Canvas: TCanvas; ARect: TRect); virtual;
    property Component: TPersistent readonly;
    property frComponent: TfrxComponent readonly;
    property Designer: TfrxCustomDesigner readonly;
    property ItemHeight: Integer;
    property PropInfo: PPropInfo readonly;
    property Value: String;
    property Values: TStrings readonly;
  end;

你也可以繼承以下任何一個類,這些類本身實現了一些處理相應型別的屬性的基本功能。

  TfrxIntegerProperty = class(TfrxPropertyEditor)
  TfrxFloatProperty = class(TfrxPropertyEditor)
  TfrxCharProperty = class(TfrxPropertyEditor)
  TfrxStringProperty = class(TfrxPropertyEditor)
  TfrxEnumProperty = class(TfrxPropertyEditor)
  TfrxClassProperty = class(TfrxPropertyEditor)
  TfrxComponentProperty = class(TfrxPropertyEditor)

在這個類中定義了幾個屬性。

  • Component - 連結到父級元件(不是屬性本身!),給定的屬性屬於該元件。
  • frComponent - 相同的,但被投到TfrxComponent型別(為了在某些情況下方便)。
  • Designer - 通往報告設計器的連結。
  • ItemHeight - 專案高度,屬性在其中顯示。它在OnDrawXXX中很有用。
  • PropInfo - 連結到PPropInfo結構,它包含了關於已編輯屬性的資訊。
  • Value - 顯示為字串的屬性值。
  • Values - 值的列表。如果定義了 "paValueList "屬性(見下文),這個屬性將被填入GetValue方法中。

下面的方法是服務性的。它們可以用來獲取或設定已編輯的屬性值。

    function GetFloatValue: Extended;
    function GetOrdValue: Integer;
    function GetStrValue: String;
    function GetVarValue: Variant;
    procedure SetFloatValue(Value: Extended);
    procedure SetOrdValue(Value: Integer);
    procedure SetStrValue(const Value: String);
    procedure SetVarValue(Value: Variant);

你應該使用與屬性型別相對應的方法。因此,如果屬性是 "Integer "型別的,就使用GetOrdValue和SetOrdValue方法。這些方法也用於處理TObject型別的屬性,因為這種屬性包含32位物件地址。在這種情況下,只要做以下型別的轉換就可以了,比如說。

MyFont := TFont(GetOrdValue)

為了建立你自己的編輯器,有必要繼承基本類,並重寫定義在公共部分的一個或幾個方法(這取決於你想實現的屬性型別和功能)。你肯定要覆蓋的方法之一是GetAttributes方法。這個方法是用來返回屬性的集合。屬性以下列方式定義。

TfrxPropertyAttribute = (paValueList, paSortList, paDialog, paMultiSelect, paSubProperties, paReadOnly, paOwnerDraw);
TfrxPropertyAttributes = set of TfrxPropertyAttribute;

屬性分配是按以下方式實現的:

  • paValueList - 屬性代表下拉式的數值列表。這個功能以 "顏色 "屬性為例)。如果這個屬性存在,GetValues方法應該被重寫。
  • paSortList - 對列表元素進行排序。它與paValueList一起使用。
  • paDialog - 屬性有編輯器。如果這個屬性存在,...按鈕將顯示在編輯行的右邊部分。通過點選它,編輯方法被呼叫。
  • paMultiSelect - 允許在同時選擇的一些物件中編輯給定的屬性。一些屬性(如 "名稱 "等)沒有這個屬性。
  • paSubProperties - 屬性是TPersistent型別的物件,並且有它自己的屬性,這些屬性也應該被顯示。這個功能在 "字型 "屬性中得到了體現)。
  • paReadOnly - 不可能在編輯行中修改值。一些屬性,作為 "類 "或 "設定 "型別,擁有這個屬性。
  • paOwnerDraw - 屬性值的繪製是通過OnDrawItem方法進行的。如果 "paValueList "屬性被定義,那麼下拉列表的繪製是通過OnDrawLBItem方法進行的。

編輯方法在兩種情況下被呼叫:要麼選擇屬性,要麼通過雙擊它的值,或者(如果屬性有paDialog屬性)通過點選...按鈕。如果屬性值被修改,這個方法應該返回 "真"。

GetValue方法應該以字串形式返回屬性值(它將顯示在物件檢查器中)。如果你繼承了TfrxPropertyEditor基本類,有必要覆蓋這個方法。

SetValue方法是用來設定屬性值轉移為字串。如果你繼承自TfrxPropertyEditor基本類,就有必要覆蓋這個方法。

如果你定義了 "paValueList "屬性,GetValues方法應該被覆蓋。這個方法應該用值來填充數值屬性。
下面三個方法允許執行手動屬性值繪製(顏色屬性編輯器以同樣的方式工作)。如果你定義了 "paOwnerDraw "屬性,這些方法將被呼叫。
OnDrawItem方法在物件檢查器中繪製屬性值時被呼叫(當屬性未被選中時;否則它的值將簡單地顯示在編輯行中)。例如,顏色屬性編輯器會在屬性值的左邊繪製矩形,並根據顏色填充。
如果你定義了 "paValueList "屬性,GetExtraLBSize方法將被呼叫。該方法返回畫素數,"下拉列表 "的寬度應該被調整,以便為顯示的圖片找到空間。預設情況下,該方法返回對應於屬性包絡的單元格高度的值。如果你需要推匯出寬度大於高度的圖片,應該重寫給定的方法。
OnDrawLBItem方法在下拉列表中繪製字串時被呼叫,如果你定義了paValueList屬性。事實上,這個方法是TListBox.OnDrawItem事件處理程式,並且有相同的引數集。
屬性編輯器的註冊是通過frxDsgnIntf檔案中描述的程式進行的。

procedure frxPropertyEditors.Register(PropertyType: PTypeInfo; ComponentClass: TClass; const PropertyName: String; EditorClass: TfrxPropertyEditorClass);
  • PropertyType - 關於屬性型別的資訊,通過 "TypeInfo "系統函式傳輸,例如TypeInfo(String)。
  • ComponentClass - 元件名稱,有你要編輯的屬性(可以是nil)。
  • PropertyName - 你要編輯的屬性的名稱(可以是空白字串)。
  • EditorClass - 屬性編輯器名稱

只需要指定 "屬性型別 "引數。"ComponentClass "和/或 "PropertyName "引數可以是空白。這允許將編輯器註冊到任何PropertyType型別的屬性、任何具體的ComponentClass元件及其繼承者的屬性,或具體元件的PropertyName具體屬性(或任何元件,如果ComponentClass引數為空)。
讓我們來看看三個屬性編輯器的例子。根據FastReport的要求,編輯器的程式碼可以放在一個檔案中,該檔案的名稱與包含元件程式碼的檔案相同,並新增編輯器的字尾。

{ TFont property editor displays editor button(...) }
{ inherit from ClassProperty }

type
 TfrxFontProperty = class(TfrxClassProperty)
  public
    function Edit: Boolean; override;
    function GetAttributes: TfrxPropertyAttributes; override;
  end;

function TfrxFontProperty.GetAttributes: TfrxPropertyAttributes;
begin
  {  property has nested properties and  editor. It cannot be edited manually }
  Result := [paMultiSelect, paDialog, paSubProperties, paReadOnly];
end;

function TfrxFontProperty.Edit: Boolean;
var
  FontDialog: TFontDialog;
begin
  { create standard dialogue }
  FontDialog := TFontDialog.Create(Application);
  try
    { take  property value }
    FontDialog.Font := TFont(GetOrdValue);
    FontDialog.Options := FontDialog.Options + [fdForceFontExist];
    { display dialogue }
    Result := FontDialog.Execute;
    { bind new value }
    if Result then
      SetOrdValue(Integer(FontDialog.Font));
  finally
    FontDialog.Free;
  end;
end;

{ registration }

frxPropertyEditors.Register(TypeInfo(TFont), nil, '', TfrxFontProperty);
{ TFont.Name property editor displays  drop-down list of available fonts }
{ inherit from StringProperty, as property is of string type }

type
  TfrxFontNameProperty = class(TfrxStringProperty)
  public
    function GetAttributes: TfrxPropertyAttributes; override;
    procedure GetValues; override;
  end;

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

procedure TfrxFontNameProperty.GetValues;
begin
  Values.Assign(Screen.Fonts);
end;

{ registration }

frxPropertyEditors.Register(TypeInfo(String), TFont, 'Name', TfrxFontNameProperty);
{ TPen.Style property editor displays picture, which is pattern of selected style }

type
  TfrxPenStyleProperty = class(TfrxEnumProperty)
  public
    function GetAttributes: TfrxPropertyAttributes; override;
    function GetExtraLBSize: Integer; override;
    procedure OnDrawLBItem(Control: TWinControl; Index: Integer;
      ARect: TRect; State: TOwnerDrawState); override;
    procedure OnDrawItem(Canvas: TCanvas; ARect: TRect); override;
  end;

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

{ method draws thick horizontal line with selected style }
procedure HLine(Canvas: TCanvas; X, Y, DX: Integer);
var
  i: Integer;
begin
  with Canvas do
  begin
    Pen.Color := clBlack;
    for i := 0 to 1 do
    begin
      MoveTo(X, Y - 1 + i);
      LineTo(X + DX, Y - 1 + i);
    end;
  end;
end;

{ drawing drop-down list }
procedure TfrxPenStyleProperty.OnDrawLBItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState);
begin
  with TListBox(Control), TListBox(Control).Canvas do
  begin
    FillRect(ARect);
    TextOut(ARect.Left + 40, ARect.Top + 1, TListBox(Control).Items[Index]);
    Pen.Color := clGray;
    Brush.Color := clWhite;
    Rectangle(ARect.Left + 2, ARect.Top + 2, ARect.Left + 36, ARect.Bottom - 2);
    Pen.Style := TPenStyle(Index);
    HLine(TListBox(Control).Canvas, ARect.Left + 3, ARect.Top + (ARect.Bottom - ARect.Top) div 2, 32);
    Pen.Style := psSolid;
  end;
end;

{ drawing property value }
procedure TfrxPenStyleProperty.OnDrawItem(Canvas: TCanvas; ARect: TRect);
begin
  with Canvas do
  begin
    TextOut(ARect.Left + 38, ARect.Top, Value);
    Pen.Color := clGray;
    Brush.Color := clWhite;
    Rectangle(ARect.Left, ARect.Top + 1, ARect.Left + 34, ARect.Bottom - 4);
    Pen.Color := clBlack;
    Pen.Style := TPenStyle(GetOrdValue);
    HLine(Canvas, ARect.Left + 1, ARect.Top + (ARect.Bottom - ARect.Top) div 2 - 1, 32);
    Pen.Style := psSolid;
  end;
end;

{ return  picture width }
function TfrxPenStyleProperty.GetExtraLBSize: Integer;
begin
  Result := 36;
end;

{ registration }
frxPropertyEditors.Register(TypeInfo(TPenStyle), TPen, 'Style', TfrxPenStyleProperty);

如果您對 FastReport 感興趣,歡迎加入 FastReport QQ 交流群:702295239