简体   繁体   中英

Add menu item to unit's tab context menu in Delphi IDE using ToolsAPI

I am looking to find out which services/interface I need to use to add an item to the right-click menu of a source file in the Delphi IDE.

For example, if I right-click on a unit's tab, it has items to "Close page", "Close all other pages", "Properties", etc. I want to add custom items to that menu, if possible.

I looked over the ToolsAPI unit but I have no clue where to begin. I assume there's an interface I can use to enumerate items and add items, but I dont know where to start looking.

If that's not possible, I'd settle for the code editor's context menu.

Maybe there's some samples online for this, but I'm still looking and have found none.

Any help appreciated.

Remy Lebeau has pointed you in exactly the right directions with his link to the GExperts guide.

If you've not done this sort of stuff before, it can still be a bit of a performance to get started on writing your own IDE add-in, so I've set out below a minimal example of how to add an item to the code editor's pop-up menu.

What you do, obviously, is to create a new package, add the unit below to it, and then install the package in the IDE. The call to Register in the unit does what's necessary to install the new item in the editor pop-up menu.

Make sure that the code editor is open at the time you install the package. The reason is that, as you'll see, the code checks whether there is an active editor at the time. I've left how to ensure that the pop-up item gets added even if there is no code editor active at the time. Hint: if you look at the ToolsAPI.Pas unit for whichever version of Delphi you're using, you'll find that it includes various kinds of notifier, and you can use a notification from at least one of them to defer checking if there is an editor active until one is likely to be.

Btw, the code adds the menu item to the context menu which pops up over the editor window itself rather than the active tab. Part of the fun with IDE add-ins is the fun of experimenting to see if you can get exactly what you want. I haven't tried it myself, but I doubt that adding the menu item to the context menu of one of the editor tabs would be that difficult - seeing as the Delphi IDE is a Delphi app, as you can see from the code below, you can use FindComponent (or just iterate over a Components collection) to find what you want. However, it is better, if you can, to locate things via the ToolsAPI interfaces. See Update below.

interface

uses
  Classes, Windows, Menus, Dialogs, ToolsAPI;

type

   TIDEMenuItem = class(TNotifierObject, IOTAWizard, IOTAMenuWizard)
     function GetName: string;
     function GetIDString: string;
     function GetMenuText: string;
     function GetState: TWizardState;
     procedure Execute;
   end;

   TIDEMenuHandler = class(TObject)
     procedure HandleClick(Sender: TObject);
   end;

procedure Register;

implementation

var
  MenuItem: TMenuItem;
  IDEMenuHandler: TIDEMenuHandler;
  EditorPopUpMenu : TPopUpMenu;

procedure TIDEMenuItem.Execute;
begin
  ShowMessage('Execute');
end;

function TIDEMenuItem.GetIDString: string;
begin
  Result := 'IDEMenuItemID';
end;

function TIDEMenuItem.GetMenuText: string;
begin
  Result := 'IDEMenuItemText';
end;

function TIDEMenuItem.GetName: string;
begin
  Result := 'IDEMenuItemName';
end;

function TIDEMenuItem.GetState: TWizardState;
begin
  Result := [wsEnabled];
end;

procedure TIDEMenuHandler.HandleClick(Sender: TObject);
begin
  ShowMessage(TIDEMenuItem(Sender).GetName + ' Clicked');
end;

procedure AddIDEMenu;
var
  NTAServices: INTAServices40;
  EditorServices: IOTAEditorServices;
  EditView: IOTAEditView;
begin
  NTAServices := BorlandIDEServices as INTAServices40;

  EditorServices := BorlandIDEServices as IOTAEditorServices;
  EditView := EditorServices.TopView;

  if Assigned(EditView) then begin
    EditorPopUpMenu := TPopUpMenu(EditView.GetEditWindow.Form.FindComponent('EditorLocalMenu'));
    Assert(EditorPopUpMenu <>Nil);

    IDEMenuHandler := TIDEMenuHandler.Create;
    MenuItem := TMenuItem.Create(Nil);
    MenuItem.Caption := 'Added IDE editor menu item';
    MenuItem.OnClick := IDEMenuHandler.HandleClick;
    EditorPopUpMenu.Items.Add(MenuItem)
  end
  else
    ShowMessage('Code editor not active');
end;

procedure RemoveIDEMenu;
begin
  if MenuItem <> Nil then begin
    EditorPopUpMenu.Items.Remove(MenuItem);
    FreeAndNil(MenuItem);
    IDEMenuHandler.Free;
  end;
end;

procedure Register;
begin
  RegisterPackageWizard(TIDEMenuItem.Create);
  AddIDEMenu;
end;

initialization

finalization
  RemoveIDEMenu;
end.

Update: The following code finds the TabControl of the editor window and adds the menu item to its context menu. However, note that it does not account for there being a second editor window open.

procedure AddIDEMenu;
var
  NTAServices: INTAServices40;
  EditorServices: IOTAEditorServices;
  EditView: IOTAEditView;
  TabControl : TTabControl;

  function FindTabControl(AComponent : TComponent) : TTabControl;
  var
    i : Integer;
  begin
    Result := Nil;
    if CompareText(AComponent.ClassName, 'TXTabControl') = 0 then begin
      Result := TTabControl(AComponent);
      exit;
    end
    else begin
      for i := 0 to AComponent.ComponentCount - 1 do begin
        if CompareText(AComponent.Components[i].ClassName, 'TXTabControl') = 0 then begin
          Result := TTabControl(AComponent.Components[i]);
          exit;
        end
        else begin
          Result := FindTabControl(AComponent.Components[i]);
          if Result <> Nil then
            exit;
        end;              
      end;
    end;
  end;

begin
  NTAServices := BorlandIDEServices as INTAServices40;

  EditorServices := BorlandIDEServices as IOTAEditorServices;
  EditView := EditorServices.TopView;

  if Assigned(EditView) then begin
    TabControl := FindTabControl(EditView.GetEditWindow.Form);
    Assert(TabControl <> Nil, 'TabControl not found');
    EditorPopUpMenu := TabControl.PopupMenu;
    Assert(EditorPopUpMenu <> Nil, 'PopUP menu not found');
    //EditorPopUpMenu := TPopUpMenu(EditView.GetEditWindow.Form.FindComponent('EditorLocalMenu'));
    Assert(EditorPopUpMenu <>Nil);

    IDEMenuHandler := TIDEMenuHandler.Create;
    MenuItem := TMenuItem.Create(Nil);
    MenuItem.Caption := 'Added IDE editor menu item';
    MenuItem.OnClick := IDEMenuHandler.HandleClick;
    EditorPopUpMenu.Items.Add(MenuItem)
  end
  else
    ShowMessage('No editor active');
end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM