Please consider such scenerio:
I have component called TMenuItemSelector which has two published properties: PopupMenu - allows to pick an instance of TPopupMenu from the form and MenuItem which allows to pick any instance of TMenuItem from the form.
I would like to modify property editor for MenuItem property in a way that when PopupMenu is assigned then only menu items from this PopupMenu are visible in a drop down list.
I know that I need to write my own descendant of TComponentProperty and override GetValues method. The problem is that I do not know how to access the form on which TMenuItemSelector is lying.
Original TComponentProperty is using this method to iterate all available instances:
procedure TComponentProperty.GetValues(Proc: TGetStrProc);
begin
Designer.GetComponentNames(GetTypeData(GetPropType), Proc);
end;
However, Designer seems to be precompiled so I have no idea how GetComponentNames works.
This is what I have so far, I guess only thing which I am missing is the implementation of GetValues:
unit uMenuItemSelector;
interface
uses
Classes, Menus, DesignIntf, DesignEditors;
type
TMenuItemSelector = class(TComponent)
private
FPopupMenu: TPopUpMenu;
FMenuItem: TMenuItem;
procedure SetPopupMenu(const Value: TPopUpMenu);
procedure SetMenuItem(const Value: TMenuItem);
published
property PopupMenu: TPopUpMenu read FPopupMenu write SetPopupMenu;
property MenuItem: TMenuItem read FMenuItem write SetMenuItem;
end;
type
TMenuItemProp = class(TComponentProperty)
public
function GetAttributes: TPropertyAttributes; override;
procedure GetValues(Proc: TGetStrProc); override;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterPropertyEditor(TypeInfo(TMenuItem), TMenuItemSelector, 'MenuItem', TMenuItemProp);
RegisterComponents('Test', [TMenuItemSelector]);
end;
{ TMenuItemSelector }
procedure TMenuItemSelector.SetMenuItem(const Value: TMenuItem);
begin
FMenuItem := Value;
end;
procedure TMenuItemSelector.SetPopupMenu(const Value: TPopUpMenu);
begin
FPopupMenu := Value;
end;
{ TMenuItemProperty }
function TMenuItemProp.GetAttributes: TPropertyAttributes;
begin
Result := inherited GetAttributes + [paValueList, paSortList];
end;
procedure TMenuItemProp.GetValues(Proc: TGetStrProc);
begin
//How to filter MenuItems from the form in a way that only
//MenuItems which belong to TMenuItemSelector.PopupMenu are displayed? \
//And how to get to that form?
//inherited;
end;
end.
Anyone could help?
Thanks.
When
TMenuItemProp.GetValues()is called, you need to look at theTMenuItemSelectorobject whoseMenuItemproperty is currently being edited, see if that object has aPopupMenuassigned, and if so then loop through its items as neded, eg:BTW, you need to implement
TMenuItemSelectorandTMenuItemPropin separate packages. With the exception of theRegisterComponents()function, (which is implemented in a runtime package), design-time code is not allowed to be compiled into run-time executables. It is against the EULA, and Embarcadero's design-time pacakges are not allowed to be distributed. You need to implementTMenuItemSelectorin a runtime-only package, and then implementTMenuItemPropandRegister()in a designtime-only package thatRequiresthe runtime-only package andusesthe unit thatTMenuItemSelectoris declared in, eg:.