5

It's not giving any erros when installing it, also tested the operators before and and they were working fin but i can't make the menu show up. I was trying to call it using "DC_MT_macro_menu" in a shortcut.

Mainly use this post as reference, though he is using panel instead of menu.

The init file

bl_info = {
    "name": "Popup Macro",
    "author": "",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "DC_MT_macro_menu",
    "description": "",
    "warning": "",
    "doc_url": "",
    "category": "",
}

}

import bpy from . macro_menu import DC_MT_macro_menu from . macro_classes import DC_OT_bevel_subdiv, DC_OT_bevel_second

classes = ( DC_MT_macro_menu, DC_OT_bevel_subdiv, DC_OT_bevel_second,

) register, unregister = bpy.utils.register_classes_factory(classes)

if name == "main": register()

The menu "macro_menu"

import bpy

class DC_MT_macro_menu(bpy.types.Menu): bl_idname = "DC_MT_macro_menu" bl_label = "Macro"

def draw(self, context):
    layout = self.layout

    layout.operator("3dview.bevel_subdiv")
    layout.operator("3dview.bevel_second")

And the operators "macro_classes"

import bpy

class DC_OT_bevel_subdiv(bpy.types.Operator): bl_idname = "3dview.bevel_subdiv" bl_label = "Subdivision Workflow" def execute(self, context): ob = context.object bm = ob.modifiers.get("Bevel")

    bm = ob.modifiers.new(name="Bevel", type='BEVEL')
    bm.segments = 2
    bm.profile = 1
    bm.limit_method = 'WEIGHT'
    bm.miter_outer = 'MITER_ARC'
    bm.use_clamp_overlap = False

    return {'FINISHED'}

class DC_OT_bevel_second(bpy.types.Operator): bl_idname = "3dview.bevel_second" bl_label = "Second Bevel" def execute(self, context): ob = context.object bm = ob.modifiers.get("Bevel")

    bm = ob.modifiers.new(name="secBevel", type='BEVEL')
    bm.limit_method = 'ANGLE'
    bm.miter_outer = 'MITER_ARC'
    bm.use_clamp_overlap = False

    return {'FINISHED'} 

Udjani
  • 117
  • 4

1 Answers1

4

Modularise your modules

IMO rather than importing and cherry picking classes from submodules, instead can import the module and call its register method.

For testing have placed the addon in a testing_testing folder, and given it the "Testing" category... will of-coarse need to rename to something more suitable.

Notice the submodules are imported from testing_testing rather than from current folder . which requires the addon must have the name specified by folder. This makes the imports viable when run from main thread. (eg tested in text editor).

Can alter the submodules by adding removing other classes without the need to edit init file. Only need to edit again for a new submodule. Can use something like pkgutils.list_modules to look for modules in root folder and automate the imports of each, hence never needing to touch init to have any module placed in folder registered.

Reworked code.

testing_testing/__init__.py

bl_info = {
    "name": "Popup Macro",
    "author": "",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "DC_MT_macro_menu",
    "description": "",
    "warning": "",
    "doc_url": "",
    "category": "Testing",
}

can use importlib.reload here instead

import bpy from testing_testing import operators, menus

modules = (operators, menus)

def register(): for m in modules: m.register()

def unregister(): for m in modules: m.unregister()

if name == "main": register()

testing_testing/operators.py

import bpy

class DC_OT_bevel_subdiv(bpy.types.Operator): bl_idname = "3dview.bevel_subdiv" bl_label = "Subdivision Workflow"

def execute(self, context):
    ob = context.object
    bm = ob.modifiers.get("Bevel")

    bm = ob.modifiers.new(name="Bevel", type='BEVEL')
    bm.segments = 2
    bm.profile = 1
    bm.limit_method = 'WEIGHT'
    bm.miter_outer = 'MITER_ARC'
    bm.use_clamp_overlap = False

    return {'FINISHED'}


class DC_OT_bevel_second(bpy.types.Operator): bl_idname = "3dview.bevel_second" bl_label = "Second Bevel"

def execute(self, context):
    ob = context.object
    bm = ob.modifiers.get("Bevel")

    bm = ob.modifiers.new(name="secBevel", type='BEVEL')
    bm.limit_method = 'ANGLE'
    bm.miter_outer = 'MITER_ARC'
    bm.use_clamp_overlap = False

    return {'FINISHED'}


classes = (DC_OT_bevel_second, DC_OT_bevel_subdiv,)

register, unregister = bpy.utils.register_classes_factory(classes)

if name == "main": register()

testing_testing/menus.py

import bpy

class DC_MT_macro_menu(bpy.types.Menu): bl_idname = "DC_MT_macro_menu" bl_label = "Macro"

def draw(self, context):
    layout = self.layout

    layout.operator("3dview.bevel_subdiv")
    layout.operator("3dview.bevel_second")


classes = (DC_MT_macro_menu,)

register, unregister = bpy.utils.register_classes_factory(classes)

if name == "main": register() # test call bpy.ops.wm.call_menu(name=DC_MT_macro_menu.bl_idname)

Note can test if a module has a register method using

if hasattr(m, "register"):
    m.register()

On linux can select the folder and compress

enter image description here

A zip file that follows convention recommended here Addons: Only some .zips will install

Note: look for the error if it is saying the folder already exists then choose overwrite option, remove previous installation (delete folder, or hit remove button on addon)

The enabled addon,

enter image description here

after which the menu can be called from for instance the python console

enter image description here

Running menus.py in text editor will also make the menu popup via a test call.

To hang your menu onto another during register, recommend writing your own register and unregister methods instead of using the factory generated methods.

Finally to make a shortcut to popup your menu, as displayed above the operator is "wm.call_menu" and set its name property to the bl_idname of your menu.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • So i copied the changes you made 1 to 1 and changed the folder name to testing_testing, just so i could test here to see if i would get any errors, and i do. When i call the menu via the text editor it works as expected, the menu popsup and work just fine. But when i try to install it the console says that the modules were installed, yet the addon checkbox won't let me "check it", and when calling the menu via the console i get an error. link. The error happens in both 2.83 and 2.90. You have any idea of what could that be? – Udjani Jun 23 '20 at 21:44
  • 1
    Try now. accidentally dropped an "n" in pasting. Had m.uregister corrected (via one character edit) to m.unregister. Look for error messages in console, eg module has no attribute uregister – batFINGER Jun 24 '20 at 03:05
  • Same problem still, it says addon not found: 'testing_testing' on the system console. I am zipping the testing_testing folder with the 3 script inside it. Is that right or should i have any of the scripts inside another folder? – Udjani Jun 24 '20 at 04:20
  • 1
    See https://blender.stackexchange.com/a/39747/15543 What is important is that there is a folder named "testing_testing" in your addons folder after installing. Note can revert back to the from . import and it won't matter what the name of folder is (as long as it can be a python module name eg no periods, slashes, sloshes etc) IMO it is much better if we know the addon will have a consistent package name. If the code above is installed in a folder named testing_testing can confirm that enabling and disabling works as expected. – batFINGER Jun 24 '20 at 04:28
  • 1
    I am so stupid, i read the init file about 10 times and only realized that i should have changed the 2 other script files names to menus and operators after you made an update to the post. Sorry for the trouble and thank you very much for the help! – Udjani Jun 24 '20 at 04:58
  • 1
    Got there in the end. The names are by way of suggestion only. Hope this helps... got to how to make a multi-file addon in the end.. lol. – batFINGER Jun 24 '20 at 05:07
  • 1
    this is a Life Saver – SHikha Mittal Apr 09 '21 at 10:35
  • Sorry if this is somehow obvious, but is it possible to load modules from different files in Blender's text editor? I could only make this work by zipping the files, files in sub folder and then installing the zip as addon. It is quite tedious to do this constantly. – ezez May 30 '21 at 09:33
  • I've followed everything you said but still I get an error ImportError: attempted relative import with no known parent package. Please help me I spend all my day to resolve this. However, I can't go more further right now. I'm using v2.93.1 – sniffingdoggo Apr 27 '22 at 13:43