2012-04-02 75 views
4

請考慮這樣之情況:如何修改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. 

任何人都可以幫助嗎?

謝謝。

+0

使用'Designer.Root'來轉換表單,我想。 – 2012-04-02 21:07:57

回答

7

TMenuItemProp.GetValues()被調用時,你需要看看TMenuItemSelector對象,其MenuItem酒店目前正在編輯,瞭解該對象是否具有分配PopupMenu,如果這樣的話作爲neded循環通過其項目,如:

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()Requires的僅運行時包和usesTMenuItemSelector被宣佈爲單位,例如:

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. 
+0

最後一段採用運行時軟件包。如果你不使用這些,那麼它會更簡單一些,但你仍然受到重新分配的限制。 – 2012-04-02 23:06:07

+1

即使運行時軟件包在使用該組件的應用程序中處於禁用狀態,您仍然必須(也應該)將運行時代碼和設計時代碼拆分爲不同的軟件包。 IDE將加載designtime包(因此它應該儘可能小),並將決定應用程序是靜態還是動態鏈接到運行時代碼。如果設計時代碼位於運行時包中,並且該運行時包靜態鏈接,則設計時代碼也會得到處理並可能鏈接進來,這是不允許的。運行時間/設計時間間隔自D6起執行。 – 2012-04-02 23:56:23

+0

謝謝雷米。還有一個問題,GetComponent(0)是如何工作的。我正在閱讀文檔,它說組件是從剪貼板中提取的,但是它如何到達剪貼板? – Wodzu 2012-04-03 05:20:35

相關問題