Search code examples
delphinotificationscustom-componentskins

How to make a CustomComponents that detect if there is new component is drop on a form


I created a Custom components SkinMgr and SkinPanel in delphi2009. i wanted the two component automatically link together even if the SkinMgr is in a DataModule or anywhere in the other form.

any help, sample or suggestion.

thank you in advance.


Solution

  • Here's a quick test with a TActionList descendant and TCustomActionManager: when an instance of TActionListEx component is dropped on a form at designtime, it enumerates all current project's modules and try to find a form/datamodule with an instance of TCustomActionManager. If it finds one, it adds the newly created TActionListEx to its LinkedActionLists collection.

    Runtime package:

    unit TestComponents;
    
    interface
    
    uses
      System.Classes, Vcl.ActnList;
    
    type
      TActionListEx = class(TActionList)
      public
        constructor Create(AOwner: TComponent); override;
      end;
      TNotifyProc = procedure(Sender: TObject);
    
    var
      CreateNotify: TNotifyProc = nil;
    
    implementation
    
    { TActionListEx }
    
    constructor TActionListEx.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      if (csDesigning in ComponentState) and Assigned(CreateNotify) then
        CreateNotify(Self);
    end;
    
    end.
    

    Design time package:

    unit TestComponentsDesign;
    
    interface
    
    procedure Register;
    
    implementation
    
    uses
      System.Classes, System.SysUtils,
      Vcl.ActnMan,
      ToolsAPI,
      TestComponents;
    
    procedure CreateNotifyProc(Sender: TObject);
    var
      ActionList: TActionListEx absolute Sender;
      ModuleServices: IOTAModuleServices;
      ActiveProject: IOTAProject;
      I, J: Integer;
      ModuleInfo: IOTAModuleInfo;
      Module: IOTAModule;
      Editor: IOTAFormEditor;
      RootComponent: IOTAComponent;
      Component: INTAComponent;
      ActionManager: TCustomActionManager;
      ActionListItem: TActionListItem;
    begin
      if not (Sender is TActionListEx) or not (csDesigning in ActionList.ComponentState) then
        Exit;
    
      if not Supports(BorlandIDEServices, IOTAModuleServices, ModuleServices) then
        Exit;
    
      ActiveProject := ModuleServices.GetActiveProject;
      if not Assigned(ActiveProject) then
        Exit;
    
      for I := 0 to ActiveProject.GetModuleCount - 1 do
      begin
        Module := nil;
        Editor := nil;
        RootComponent := nil;
    
        ModuleInfo := ActiveProject.GetModule(I);
        if Assigned(ModuleInfo) and (ModuleInfo.FormName <> '') then
          Module := ModuleInfo.OpenModule;
    
        if Assigned(Module) then
          for J := 0 to Module.ModuleFileCount - 1 do
            if Supports(Module.ModuleFileEditors[J], IOTAFormEditor, Editor) then
              Break;
    
        if Assigned(Editor) then
          RootComponent := Editor.GetRootComponent;
    
        if Assigned(RootComponent) then
          for J := 0 to RootComponent.GetComponentCount - 1 do
            if Supports(RootComponent.GetComponent(J), INTAComponent, Component) and (Component.GetComponent is TCustomActionManager) then
            begin
              ActionManager := TCustomActionManager(Component.GetComponent);
              ActionListItem := ActionManager.LinkedActionLists.Add as TActionListItem;
              try
                ActionListItem.ActionList := ActionList;
                Editor.MarkModified;
                Exit;
              except
                ActionListItem.Free;
                raise;
              end;
            end;
      end;
    end;
    
    procedure Register;
    begin
      RegisterComponents('Test', [TActionListEx]);
      CreateNotify := CreateNotifyProc;
    end;
    
    initialization
    
    finalization
      CreateNotify := nil;
    
    end.