delphi – 如何修改TComponentProperty以仅在下拉列表中显示特定
请考虑这样的场景:
我有一个名为TMenuItemSelector的组件,它有两个已发布的属性:PopupMenu – 允许从表单中选择TPopupMenu的实例,而MenuItem允许从表单中选择任何TMenuItem实例. 我想以一种方式修改MenuItem属性的属性编辑器,当分配PopupMenu时,只有来自此PopupMenu的菜单项在下拉列表中可见. 我知道我需要编写自己的TComponentProperty后代并覆盖GetValues方法.问题是我不知道如何访问TMenuItemSelector所在的表单. 原始TComponentProperty使用此方法迭代所有可用实例: procedure TComponentProperty.GetValues(Proc: TGetStrProc); begin Designer.GetComponentNames(GetTypeData(GetPropType),Proc); end; 但是,Designer似乎是预编译的,所以我不知道GetComponentNames是如何工作的. 这是我到目前为止所做的,我想我唯一缺少的是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. 有人可以帮忙吗? 谢谢. 解决方法
当调用TMenuItemProp.GetValues()时,您需要查看当前正在编辑其MenuItem属性的TMenuItemSelector对象,查看该对象是否已分配PopupMenu,如果是,则循环遍历其项目,例如:
procedure TMenuItemProp.GetValues(Proc: TGetStrProc); var Selector: TMenuItemSelector; I: Integer; begin Selector := GetComponent(0) as TMenuItemSelector; if Selector.PopupMenu <> nil then begin with Selector.PopupMenu.Items do begin for I := 0 to Count-1 do Proc(Designer.GetComponentName(Items[I])); end; end else inherited GetValues(Proc); end; 顺便说一句,您需要在单独的包中实现TMenuItemSelector和TMenuItemProp.除了RegisterComponents()函数(在运行时包中实现)之外,不允许将设计时代码编译为运行时可执行文件.这是针对EULA的,Embarcadero的设计时间版本不允许分发.您需要在仅运行时的包中实现TMenuItemSelector,然后在仅设计时的包中实现TMenuItemProp和Register(),该包需要仅运行时包并使用声明TMenuItemSelector的单元,例如: unit uMenuItemSelector; interface uses Classes,Menus; type TMenuItemSelector = class(TComponent) private FPopupMenu: TPopUpMenu; FMenuItem: TMenuItem; procedure SetPopupMenu(const Value: TPopUpMenu); procedure SetMenuItem(const Value: TMenuItem); protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; published property PopupMenu: TPopUpMenu read FPopupMenu write SetPopupMenu; property MenuItem: TMenuItem read FMenuItem write SetMenuItem; end; implementation { TMenuItemSelector } procedure TMenuItemSelector.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if Operation = opRemove then begin if AComponent = FPopupMenu then begin FPopupMenu := nil; FMenuItem := nil; end else if AComponent = FMenuItem then begin FMenuItem := nil; end; end; end; procedure TMenuItemSelector.SetMenuItem(const Value: TMenuItem); begin if FMenuItem <> Value then begin if FMenuItem <> nil then FMenuItem.RemoveFreeNotification(Self); FMenuItem := Value; if FMenuItem <> nil then FMenuItem.FreeNotification(Self); end; end; procedure TMenuItemSelector.SetPopupMenu(const Value: TPopUpMenu); begin if FPopupMenu <> Value then begin if FPopupMenu <> nil then FPopupMenu.RemoveFreeNotification(Self); FPopupMenu := Value; if FPopupMenu <> nil then FPopupMenu.FreeNotification(Self); SetMenuItem(nil); end; end; end. . unit uMenuItemSelectorEditor; interface uses Classes,DesignEditors; type TMenuItemSelectorMenuItemProp = class(TComponentProperty) public function GetAttributes: TPropertyAttributes; override; procedure GetValues(Proc: TGetStrProc); override; end; procedure Register; implementation uses Menus,uMenuItemSelector; procedure Register; begin RegisterComponents('Test',[TMenuItemSelector]); RegisterPropertyEditor(TypeInfo(TMenuItem),TMenuItemSelectorMenuItemProp); end; { TMenuItemSelectorMenuItemProp } function TMenuItemSelectorMenuItemProp.GetAttributes: TPropertyAttributes; begin Result := inherited GetAttributes + [paValueList,paSortList] - [paMultiSelect]; end; procedure TMenuItemSelectorMenuItemProp.GetValues(Proc: TGetStrProc); var Selector: TMenuItemSelector; I: Integer; begin Selector := GetComponent(0) as TMenuItemSelector; if Selector.PopupMenu <> nil then begin with Selector.PopupMenu.Items do begin for I := 0 to Count-1 do Proc(Designer.GetComponentName(Items[I])); end; end else inherited GetValues(Proc); end; end. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |