Reputation:
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
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!
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).
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
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