How to add a Button to the Toolbar using Python?

Heyo,

I’ve spent hours Googling about this and trying to find videos, the closes I got is this script:

import unreal

def main():
    print("Creating Menus!")
    menus = unreal.ToolMenus.get()

    # Find the 'Main' menu, this should not fail,
    # but if we're looking for a menu we're unsure about 'if not'
    # works as nullptr check,
    main_menu = menus.find_menu("LevelEditor.MainMenu")
    if not main_menu:
        print("Failed to find the 'Main' menu. Something is wrong in the force!")

    entry = unreal.ToolMenuEntry(
                                name="Python.Tools",
                                # If you pass a type that is not supported Unreal will let you know,
                                type=unreal.MultiBlockType.MENU_ENTRY,
                                # this will tell unreal to insert this entry into the First spot of the menu
                                insert_position=unreal.ToolMenuInsert("", unreal.ToolMenuInsertType.FIRST)
    )
    entry.set_label("YourMenuItemName")
    # this is what gets executed on click
    entry.set_string_command(unreal.ToolMenuStringCommandType.PYTHON, custom_type='Test', string=("from bitbake import build;build()"))
    # add a new menu called PyTools to the MainMenu bar. You should probably rename the last 3 properties here to useful things for you
    script_menu = main_menu.add_sub_menu(main_menu.get_name(), "BitCakeTools", "BitCake", "BitCake")
    # add our new entry to the new menu
    script_menu.add_menu_entry("Scripts",entry)
    # refresh the UI
    menus.refresh_all_widgets()


if __name__ == '__main__':
  main()

Which is a good script and shows how to add a button to the top menu of the engine.
My problem (I think) is with that LevelEditor.MainMenu, I don’t know where the person got that information from, how did he find that namespace exactly?

Because instead of pointing to the Top menu I want to point to the Toolbar.

This doesn’t seem to be documented anywhere and I cannot find a way to maybe get all menus and iterate over them to figure out their names and try one by one.

Could a kind soul please point me in the right way?

Thanks a ton

1 Like
import unreal

def list_menu(num=1000):
    menu_list = set()
    for i in range(num):
        obj = unreal.find_object(None,"/Engine/Transient.ToolMenus_0:ToolMenu_%s" % i)
        if not obj:
            continue
        menu_name = str(obj.menu_name)
        if menu_name != "None":
            menu_list.add(menu_name)
    return list(menu_list)

print(list_menu())
LogPython: ['LevelEditor.LevelEditorToolBar', 'ContentBrowser.AssetContextMenu.LevelSequence', 'MediaPlayer.AssetPickerAssetContextMenu', 'ContentBrowser.AssetContextMenu', 'LevelEditor.LevelEditorToolBar.CompileComboButton', 'MainFrame.MainMenu', 'LevelEditor.MainMenu.Edit', 'LevelEditor.LevelEditorToolBar.BuildComboButton.LightingInfo.LightingResolution', 'LevelEditor.MainMenu', 'LevelEditor.MainMenu.File', 'AssetEditor.SkeletalMeshEditor.ToolBar', 'MainFrame.MainMenu.Edit', 'ContentBrowser.AssetContextMenu.CameraAnim', 'LevelEditor.MainMenu.Window', 'LevelEditor.LevelEditorToolBar.BuildComboButton', 'LevelEditor.LevelEditorToolBar.BuildComboButton.LightingQuality', 'MainFrame.MainMenu.File', 'LevelEditor.LevelEditorToolBar.BuildComboButton.LightingInfo.LightingDensity', 'LevelEditor.ActorContextMenu', 'ContentBrowser.AssetContextMenu.SoundWave', 'MainFrame.MainTabMenu.File', 'LevelEditor.LevelEditorToolBar.SourceControl', 'LevelEditor.LevelEditorToolBar.BuildComboButton.LightingInfo', 'LevelEditor.LevelEditorSceneOutliner.ContextMenu', 'MainFrame.MainMenu.Window', 'LevelEditor.LevelEditorToolBar.LevelToolbarQuickSettings', 'MainFrame.MainMenu.Asset', 'LevelEditor.LevelEditorToolBar.Cinematics', 'LevelEditor.MainMenu.Help', 'LevelEditor.LevelEditorToolBar.EditorModes', 'MainFrame.MainMenu.Help', 'ContentBrowser.FolderContextMenu', 'LevelEditor.LevelEditorToolBar.OpenBlueprint']

That’s the solution I found, pure python.
I write a blog article for how to extend it

1 Like

Hey! I had found your blogpost and looked into it to find a solution to my issue before posting here, you helped a bit but I couldn’t find the entire solution. Thanks a ton for writing those blogposts! You’re amazing :slight_smile:

I’ll try this code in a bit

How do you find the “LevelEditor.MainMenu” and “LevelEditor.LevelEditorToolBar” names? This isn’t documented anywhere, did you read the C++ code? Could you elaborate a bit on where to find all those names?

The name “LevelEditor.MainMenu” is registered in C++ , you could find all the registered menu in ToolMenus.cpp .

https://docs.unrealengine.com/en-US/API/Developer/ToolMenus/UToolMenus/index.html

it had a private varaiable menus, contained all the related UToolMenu.


how to get all the menu name, you can try with the list_menu method I show above.

1 Like

Hey, I know it’s been a year, any chance you’ve figured out how this would work for UE5? it’s not working for me with your method.

Also a sidenote, in the find_menu function,
obj = unreal.find_object(None,"/Engine/Transient.ToolMenus_0:ToolMenu_%s" % i)
now on UE5 is:
obj = unreal.find_object(None,"/Engine/Transient.ToolMenus_0:RegisteredMenu_%s" % i)

1 Like


Hi, highly recommended to try this plug-in TAPython, we can create buttons, slate UIs, and tools in minutes. Release Repo

1 Like

cool beans, i’ll check it out

Hi everyone, I try to acess the LevelEditorToolBar but it’s return non.
menus = unreal.ToolMenus.get() toolBarMenu = menus.find_menu("LevelEditorToolBar"). Does anyone know how to acess it?

Edit → Editor Preferences

Enable the Tools Menu Edit in the command line

Image 03

This will help you see all the various names that Unreal uses for the various Toolbars and Menus. In this case the sequencer was the target so we get the names from there

To get the icon we want, we use the Atlas found in Tools → Debug → Widget Reflector

Image 05

Run the script below, And Voila, A very big button in the Sequencer, I guess you can tone in down use a smaller icon

import unreal 

# ========== Some Class.py somewhere 
@unreal.uclass()
class PythonButtonExample(unreal.ToolMenuEntryScript):
    @unreal.ufunction(override=True)
    def execute(self, context):
        print("Wow! Print is still the king of debug! LOL")

# ========== End of Button Example

menus = unreal.ToolMenus.get()

# "Sequencer.MainToolBar" <- You can change this to be any part or
# Unreal, I just so happened to need a button for the sequencer
sequencerMenu = menus.extend_menu("Sequencer.MainToolBar")


menuScriptData = unreal.ToolMenuEntryScriptData( menu = sequencerMenu.menu_name,
                                # section = "Sequencer.MainToolBar",
                                name = "SomeName",
                                label = "Refresh Camera",
                                tool_tip = "Re Import the Camera Animation In a Jiffy",

                                # The icons you an get them from the Tools -> Debug -> Widget Reflector
                                icon = unreal.ScriptSlateIcon("EditorStyle", "ClassThumbnail.CameraAnim"),
                                insert_position = unreal.ToolMenuInsert("LevelSequenceEditor", unreal.ToolMenuInsertType.FIRST ) )

menuScript = PythonButtonExample()
menuScript.set_editor_property("data", menuScriptData)

entry = unreal.ToolMenuEntry(   name = "SomeNameEntry",
                                type = unreal.MultiBlockType.TOOL_BAR_BUTTON,
                                script_object = menuScript )

sequencerMenu.add_menu_entry("LevelSequenceEditor", entry)
menus.refresh_all_widgets()

Final Result

1 Like