user1175743
user1175743

Reputation:

Writing Property Editors - I need some guidance

Overview

I am creating a component that derives from TCustomTreeView, I want to add a property that shows in the Object Inspector a dropdown list (paValueList?). This list must be dynamically populated based on another list (TStrings) that is attached to my control, eg it could be items from a TComboBox, TListBox or strings from a TStringList etc.

I am having a few problems though and I really could do with some guidance and advice.


Code Layout

I have shortened down the code to keep it easier to read but the layout is essentially the same as what I have.

I have seperated my component packages into two (same project group), Package1 consists the component code (eg my component derived from TCustomTreeView) and Package2 contains the register procedure and designer units (designide.dcp, DesignIntf, DesignEditors etc).

Package2 is where I believe I need to add my property editor which will be used for my component derived from TCustomTreeView in Package1.

Package1

unit MyTreeViewUnit;

implementation

uses
  ...
  Classes,
  SysUtils;

type
  TMyTreeView = class(TCustomTreeView)
  private
    FSomeList: TStringList; // property editor should be filled using this list
    procedure SetSomeList(const Value: TStringList);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property SomeList: TStringList read FSomeList write SetSomeList;
  end;

  ....

Package2

unit MyTreeViewPropUnit;

implementation

uses
  DesignIntf,
  DesignEditors,
  Classes;

type
  TMyTreeViewProperty = class(TStringProperty)
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
    procedure Edit; override;
  end;

implementation

uses
  MyTreeViewUnit;  

function TMyTreeViewProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paValueList]; ?
end;

procedure TMyTreeViewProperty.GetValues(Proc: TGetStrProc);
begin
  inherited;
  // These cannot be added here!!
  // This list should be populated based on SomeList found in Package1 - MyTreeViewUnit.pas
  Proc('Item1');
  Proc('Item2');
end;

procedure TMyTreeViewProperty.Edit;
begin
  inherited;
  // ?
end;

unit MyCompsRegister;

interface

uses
  Classes;

procedure Register;

implementation

uses
  MyTreeViewUnit;
  MyTreeViewPropUnit;  

procedure Register;
begin
  RegisterComponents('MyTree', TMyTreeView);
  RegisterPropertyEditor(TypeInfo(String), TMyTreeView 'Test', TMyTreeView); // does not seem to add to object inspector for the component TMyTreeView
end;

end.

Problem

  1. The first issue is I have no idea if what I am doing is the correct approach or not, my component installs and I can use it without problem, although my property editor 'Test' is not showing up!

  2. The second issue is the way GetValues will be populated. Looking at some articles online has given me a basic insight into what I have so far in terms of filling my property editors etc. This cannot be added in this way though for what I need, in this example I need GetValues to populate based on the strings assigned to SomeList in the first unit (as I said before FSomeList could be TListBox for example).

  3. This relates to problem 2 in how can I get my property editor (when working) to communicate with my treeview so I can populate it accordingly?

I would be truly grateful if someone could give me some pointers, or better still direct me to a good article/guide on writing property editors. The ones I have read such as on Delphi.about, DelphiDabbler etc are not easy for me to understand and follow (I get confused and bogged down with problems rather easily).

Many thanks!

Upvotes: 4

Views: 1066

Answers (1)

Cosmin Prund
Cosmin Prund

Reputation: 25678

This is too long for a comment, and I want to include a bit of code, so here it goes an answer. First of all, your question is very broad. You need to brake things up so you can ask to-the-point questions. I actually started answering your Number 2 question, and I wrote something that was unreadable long before giving up!

You should start with the code that doesn't require an property editor, ie, the normal, run-time code. The property editor can't be central to the development of your custom control, because the property editor is only used at design time to speed things up. If the changes made by the Property Editor are to be persistent then they're saved to published properties visible in Object Inspector any way (*1), and those properties are in turn saved to the DFM file. That same process is reverted at run-time when the form is created and at design time when you re-open the form (example: if you close the IDE and re-open it). Since everything needs to go into Object Inspector you can skip the fancy property editors and make your control work!

What prompted me to say this:

procedure TMyTreeViewProperty.GetValues(Proc: TGetStrProc);
begin
  inherited;
  // These cannot be added here!!
  // This list should be populated based on SomeList found in Package1 - MyTreeViewUnit.pas
  Proc('Item1');
  Proc('Item2');
end;

That comment tells me you haven't figured out yet how to link your component to a different component! That's actually a trivial step, and once you've got that working you could do this:

procedure TMyTreeViewProperty.GetValues(Proc: TGetStrProc);
var s: string;
begin
  if Assigned(FLinkedCombo) then
    for s in FLinkedCombo.Items do
      Proc(s); // Beware, written in Browser!
end;

Even those it's trivial, an answer to the question as stated would be incomplete without that part, and that part includes a long talk on TComponent.FreeNotification, TComponent.RemoveFreeNotification and TComponent.Notification!

Once you've got most things working you can start work on any Property Editor you might want to create. That work will also be done as a normal project: Your aim is to create a simple form (example TMyComponentsEditor) that would be able to edit your property or component. Once you've got that working you'd be able to ask: How do I make this working editor available at DesignTime as a Property or Component Editor.

*1) Sure, the Component Editor could do fancy stuff involving multiple components; It could also persist stuff using alternate methods (ie: not relying on simple published properties).

Upvotes: 6

Related Questions