본문 바로가기

Code/cinema4d & 3dsmax

[3dsMax python] Menu & Macroscript with pymxs

 

Menu

맥스에 맨위에 메뉴바가 있는데 여기를 코드로 수정, 추가하는 법을 알아보려고 합니다.

 

기존메뉴에 추가/삭제

3ds Max 2021 버전에서는 런타임 글로벌 변수를 쉽게 만들수 있지만(rt.a = 'hi'), 그 하위 버전에는 아래 코드 처럼 만들어야 합니다.ㅜㅜ (한참 찾음)

 

그리고 매크로 스크립트를 생성해주고, 메뉴아이템을 만들어 줍니다.

 

from pymxs import runtime as rt
import re

def myfunc():
    print 'Hello'

rt.execute('global abcd')
rt.globalVars.set('abcd', myfunc)

# category, macroName, tooltip, text, function
t = rt.macros.new('test', 'velbie', 'this is toolkit', 'button', 'abcd()')
help_menu = rt.menuMan.findMenu('&Help')
# macro_name, category
menu_item = rt.menuMan.createActionItem('velbie', 'test')

help_menu.addItem(menu_item, -1)
rt.menuMan.updateMenuBar()

#remove
#help_menu = rt.menuMan.findMenu('&Rendering')
#help_menu.removeItem(menu_item)

 

메뉴상태 원상복귀

C:\Users\Velbie\AppData\Local\Autodesk\3dsMax\2018 - 64bit\ENU\en-US\UI\Workspaces\usersave\Workspace1__usersave__.mnux

저는 이 파일을 미리 복사해서 백업해두는 방법을 사용하다가 아래 방법을 사용하고 있습니다.

아래 캡쳐처럼 맨오른쪽에 default 상태로 메뉴 되돌리기를 눌르는 겁니다! (작업하면서 정말 많은 도움이 되었습니다 ㅠㅠ) Alnold 메뉴까지 없어지는걸 조심해야합니다

 

 

새로운 메뉴 만들기

 

아놀드 메뉴 포함 총 16개 거기에 15 index 에 생성해봤습니다.

index가 1부터 시작하는지 Arnold 메뉴 앞에 생겼습니다.

메뉴에는 아이템을 등록해야합니다.

메뉴에 메뉴를 등록하고 싶으면 메뉴 - 아이템 - 메뉴 이런식으로 등록해야합니다. 

 

 

from pymxs import runtime as rt

main_menu = rt.menuMan.GetMainMenuBar()
menu = rt.menuMan.createMenu('Hello')
sub_menu_item = rt.menuMan.createSubMenuItem('Hi', menu)

sub_menu_index = main_menu.numItems() - 1

main_menu.addItem(sub_menu_item, sub_menu_index)
rt.menuMan.updateMenuBar()

 

 

예제로 하나 만들어봤습니다. 매크로를 그냥 함수호출이 아닌 파일호출을 해도 괜찮을것 같습니다.

아래 코드를 사용하시면 될것 같습니다. (deep함수는 꺼내서 쓰는게 좋을것 같습니다)

 

from pymxs import runtime as rt
# Retrieve the main menu bar.


def add_to_main_menu_bar(menu):
    main_menu = rt.menuMan.GetMainMenuBar()
    sub_menu_index = main_menu.numItems() - 1
    sub_menu_item = rt.menuMan.createSubMenuItem('-', menu)

    main_menu.addItem(sub_menu_item, sub_menu_index)
    rt.menuMan.updateMenuBar()


def add_to_menu(menu, title, func):
    macro_name = func.replace('()', '')
    # category, macroName, tooltip, text, function
    t = rt.macros.new('test', macro_name, 'this is toolkit', '', func)
    # macro_name, category
    menu_action = rt.menuMan.createActionItem(macro_name, 'test')
    menu_action.setUseCustomTitle(True)
    menu_action.setTitle(title)
    menu.addItem(menu_action, -1)


def add_deep_to_menu(menu, title, func):
    test_menu = rt.menuMan.createMenu('Test_Menu')
    sub_menu_item = rt.menuMan.createSubMenuItem('-', test_menu)
    add_to_menu(test_menu, title, func)
    menu.addItem(sub_menu_item, -1)
    rt.menuMan.updateMenuBar()


def add_separator(menu):
    sep = rt.menuMan.createSeparatorItem()
    menu.addItem(sep, -1)


def add_func_to_global(var, func):
    rt.execute('global ' + var)
    rt.globalVars.set(var, func)


def myfunc():
    print 'foo'


def myfunc2():
    print 'bar'


# I think I can register only action and subMenuItem.
if __name__ == '__main__':
    add_func_to_global('abcd', myfunc)
    add_func_to_global('efgh', myfunc2)

    menu = rt.menuMan.createMenu('Velbie')
    add_to_main_menu_bar(menu)
    add_to_menu(menu, 'sayHello', 'abcd()')
    add_separator(menu)
    add_deep_to_menu(menu, 'hi', 'efgh()')

 

메뉴 삭제

메뉴를 만들었는데 삭제하고 싶을 때, 저는 하다보니깐 같은 메뉴가 여러개 생겨서 아래와 같이 사용을했습니다.

 

    while rt.menuMan.findMenu('MyMenu'):
        rt.menuMan.unRegisterMenu(rt.menuMan.findMenu('MyMenu'))

 

메뉴안에 아이템 삭제

아래 코드는 CGTalk 에서 퍼온 코드입니다.

 

from pymxs import runtime as mxRt
def remove_AllItemsFromMenu(inMenu, removeTopMenu=False):
   """
      Rercursively remove all items and sub items from the givem menu.
   """
   
   menuCount = inMenu.numItems()
   for menuIndex in reversed(xrange(1, menuCount + 1)):

      menu    = inMenu.getItem(menuIndex)
      subMenu = menu.getSubMenu()
      if subMenu:

         remove_AllItemsFromMenu(subMenu, removeTopMenu=True)

      inMenu.removeItem(menu)
   if removeTopMenu:

      mxRt.menuMan.unRegisterMenu(inMenu)

   return mxRt.menuMan.updateMenuBar()
   
# Requires a menu called "TestMenu" to exist:
# menu = mxRt.menuMan.findMenu("TestMenu")
# remove_AllItemsFromMenu(menu)
   

참고 자료

Maxscript menuman interface:

help.autodesk.com/view/3DSMAX/2017/ENU/?guid=__files_GUID_1374EDCA_CC8B_4B43_81A5_6ED98DBE01D3_htm

 

Remove menu and all it's sub menu's:

forums.cgsociety.org/t/customise-user-interface/1705754/8

 

add to menu github:

github.com/shotgunsoftware/tk-3dsmax/blob/1535e761034e06661b0f47e9ff2cbba9ab0fcf3a/plugins/basic/python/tk_3dsmaxplus_basic/plugin_bootstrap.py#L294

 

book:

books.google.co.kr/books?id=5r8WEAAAQBAJ&pg=PT39&lpg=PT39&dq=%22rt.menuMan%22&source=bl&ots=qMkanTJEqf&sig=ACfU3U2dPNhjA_N9qOyIG936_WazjX5koQ&hl=en&sa=X&ved=2ahUKEwiv94eZgsjuAhWDOnAKHdQCDAsQ6AEwAnoECAMQAg#v=onepage&q=%22rt.menuMan%22&f=false

 

AND-github:

github.com/ADN-DevTech/3dsMax-Python-HowTos/blob/master/src/packages/menuhook/menuhook/__init__.py