gpt4 book ai didi

delphi - 如何修改 TComponentProperty 以仅显示下拉列表中的特定项目?

转载 作者:行者123 更新时间:2023-12-03 15:23:57 25 4
gpt4 key购买 nike

请考虑这样的场景:

我有一个名为 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;

顺便说一句,您需要在单独的包中实现TMenuItemSelectorTMenuItemProp。除了 RegisterComponents() 函数(在运行时包中实现)之外,不允许将设计时代码编译为运行时可执行文件。它违反了 EULA,并且不允许分发 Embarcadero 的设计时包。您需要在仅运行时包中实现 TMenuItemSelector,然后在仅设计时包中实现 TMenuItemPropRegister() >需要仅运行时包并使用声明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, DesignIntf, 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), TMenuItemSelector, 'MenuItem', 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.

关于delphi - 如何修改 TComponentProperty 以仅显示下拉列表中的特定项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9983606/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com