» Back to Documentation

Don't forget to reference the required namespaces:

using Autodesk.Max;
using Autodesk.Max.Plugins;

First lets define our action item:

internal class MyAction : ActionItem

{

       const string ActionName = "My Action";

       public override string ButtonText

       {

              get { return ActionName; }

       }

 

       public override string CategoryText

       {

              get { return Plugin.ProjectName; }

       }

 

       public override string DescriptionText

       {

              get { return ActionName + " " + Plugin.ProjectName; }

       }

 

       public override bool ExecuteAction()

       {

              // execute me

              return true;

       }

 

       public override IMaxIcon Icon

       {

              get { return null; }

       }

 

       public override int Id

       {

              get { return 1; }

       }

 

       public override bool IsChecked

       {

              get { return false; }

       }

 

       public override bool IsEnabled

       {

              get { return true; }

       }

 

       public override bool IsItemVisible

       {

              get { return true; }

       }

 

       public override string MenuText

       {

              get { return "&" + ActionName + "..."; }

       }

}

Then we declare some class variables that we will keep track of. These are stored inside out IPlugin-derived class.

IIMenu menu = null;
IIMenuItem menuItem = null;
IIMenuItem menuItemMyAction = null;
uint idActionTable = 0;
IActionTable actionTable = null;
IActionCallback actionCallback = null;

We need to declare one additional 'dummy' class to enable our action to execute:

public class ZKActionCallback : ActionCallback
    {
        public override bool ExecuteAction( int id )
        {
            // Do nothing...
            return true;
        }
    }

Inside the IPlugin.Initialize() method we call MenusAndActionsRegister(), which is defined as follows:

void MenusAndActionsRegister()
        {
            IIActionManager actionManager = global.COREInterface.ActionManager;
            IIMenuManager menuManager = global.COREInterface.MenuManager;

            IActionTable actionTable = null;
            // Set up global actions
            {
                idActionTable = (uint)actionManager.NumActionTables;

                string actionTableName = ProjectName + " Actions";
                actionTable = Global.ActionTable.Create( idActionTable, 0, ref actionTableName );
                actionTable.AppendOperation( new ActionItems.MyAction() );
                actionCallback = new MyActionCallback();

                actionManager.RegisterActionTable( actionTable );
                actionManager.ActivateActionTable( actionCallback as ActionCallback, idActionTable );
            }
            // Set up menu
            {
                this.menu = menuManager.FindMenu( ProjectName );

                if( this.menu != null )
                {
                    menuManager.UnRegisterMenu( menu );
                    global.ReleaseIMenu( menu );
                    this.menu = null;
                }

                this.menuItemZookeeper = global.IMenuItem;
                this.menuItemZookeeper.Title = ProjectName;

                // Main menu
                {
                    this.menu = global.IMenu;
                    this.menu.Title = ProjectName;
                    menuManager.RegisterMenu( menu, 0 );

                    // Launch option
                    {
                        this.menuItemMyAction = global.IMenuItem;
                        this.menuItemMyAction.Title = "&MyAction";
                        this.menuItemMyAction.ActionItem = actionTable[0];

                        menu.AddItem( this.menuItemMyAction, -1 );
                    }
                }
                this.menuItem.SubMenu = menu;

                menuManager.MainMenuBar.AddItem( this.menuItem, -1 );

                global.COREInterface.MenuManager.UpdateMenuBar();
            }
        }

Finally, when unloading our plugin it is preferrable that we also unregister all the menus. We do this in the IPlugin.Cleanup() method by calling the following function:

void MenusAndActionsUnregister()
        {
            if( this.actionTable != null )
            {
                this.Global.COREInterface.ActionManager.DeactivateActionTable( actionCallback, idActionTable );
            }

            // Clean up menu
            if( this.menu != null )
            {
                this.Global.COREInterface.MenuManager.UnRegisterMenu( menu );
                this.Global.ReleaseIMenu( menu );
                this.Global.ReleaseIMenuItem( menuItemMyAction );
                this.Global.ReleaseIMenuItem( menuItem );

                this.menu = null;
                this.menuItem = null;
            }
        }

And we're done!

 
Comments
 

where is  ActionItem?

what namespace?

i cant find this

Sorry for delayed reply. It is in Autodesk.Max.Plugins namespace so include the following:

using Autodesk.Max;
using Autodesk.Max.Plugins;

Marsel Khadiyev (Software Developer, EPHERE Inc.)

Hello...

This is my first post on this forum, so let met first congratulates you on this wonderful tool. Max.NET is the solution I was looking for.

Even though I've been doing Maxscript for more than 10 years, I'm new to the Max SDK.

I'm adapting your Menu example to build my own. The main difference is that my menu has more than one menu item in it.

So from what I can understand from your code, if I need to create more MyAction classes and more menuItemMyAction. So far I'm ok.

The thing that is confusing is the action table.

First is the ActionCallback class. Is it specific per ActionItem sub-classes or it is used for the whole action table and there is only one ? I've put a break point in it and it's function is never called.

Second, is the actionTable value. Is there one for all the actions ? Or one table per action.

The name of the value implies that there is a unique table for all the action, but if it is the case, then the following lines implies that there is a single callback for all the items.

actionManager.RegisterActionTable( actionTable );
actionManager.ActivateActionTable( actionCallback as ActionCallback, idActionTable );

For the same reason, I'm wondering is the idActionTable value is the index of the table or the index of the action in the table.

Thank you for your help...

 

Hi Jonathan and welcome.

I wouldn't worry about the action callback, I don't use it myself (hence the 'do nothing' comment). You should handle your action code inside the ExecuteAction() function of ActionItem. You only need one action table for all your actions. Hope this helps.

Marsel Khadiyev (Software Developer, EPHERE Inc.)

Thanks a lot !