I’m not sure of what you mean.
I guess I should show a real example.
I know it’s not always a good idea to always compare Blender to how other softwares do and the BF doesn’t want to just copy whatever other solutions do, but it so happens that the other software I have the most experience programming with, and in Python, is Maya. And it has some nice features I highly miss. Don’t take this as a person venting out frustration (even though I am frustrated), I just want to point out where I’m coming from. I don’t pretend everything Maya does is better nor that Blender should copy it nor that it’s an easy task to change anything in any direction.
Make a button for a Python addon
In Maya
If somewhere in an addon I wanted to just make a button that just sets the current scene frame to frame 10, here’s what it could look like in Maya (just for the “create a button that does this” part):
cmds.button(label="Set Frame 10", command="cmds.currentTime(10,edit=True)")
That’s it. cmds.button
makes the button, and I tell what to execute via its command flag. I can write either a straight maya py command, or I could also define a python function containing what I want to do, and put the function name after command=
. End of story. Simple and efficient.
Full code to just make such button somewhere, it’s just a matter of defining a function that creates ui elements and calling that function:
import maya.cmds as cmds
def showUI():
myWin = cmds.window(title="A window where to put a button", widthHeight=(356,24))
cmds.columnLayout()
cmds.button(label="Set Frame 10", command="cmds.currentTime(10,edit=True)")
cmds.showWindow(myWin)
showUI()
I have now a button that jumps to frame 10:
If I wanted to have such a button visible at startup without requiring to run it manually, the easiest way would be to instead use the shelf, which is an even easier solution I explain down bellow.
But otherwise, it’s as easy as putting your script in this file: %USERPROFILE%\documents\maya\<version>scripts\userSetup.py
But called via executeDeffered() like this:
import maya.cmds as cmds
from maya.utils import executeDeferred
def showUI():
myWin = cmds.window(title="A window where to put a button", widthHeight=(356,24))
cmds.columnLayout()
cmds.button(label="Set Frame 10", command="cmds.currentTime(10,edit=True)")
cmds.showWindow(myWin)
executeDeferred(showUI)
It remains somewhat simple and fast to do. But again: there’s an even simpler solution I detail below.
In Blender
If bpy was “a bit more like maya”, we could make such button like this:
self.layout.button(text="Jump to frame 10", command="bpy.context.scene.frame_current = 10")
And, in a full code, we need to make a form of UI through a python class that needs to be registered, like this sidebar panel (i used the simple panel template):
import bpy
class TEST_PT_Panel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "SetFrame"
bl_category = 'Item'
def draw(self, context):
layout = self.layout
self.layout.button(text="Set frame 10", command="bpy.context.scene.frame_current = 10")
def register():
bpy.utils.register_class(HelloWorldPanel)
def unregister():
bpy.utils.unregister_class(HelloWorldPanel)
if __name__ == "__main__":
register()
It’s a bit longer and trickier, but it’s still simple, right? Unfortunately: that isn’t possible AFAIK.
So first, our simple “do this” must be put in an operator that needs to be registered.
import bpy
class TEST_OT_setFrame10(bpy.types.Operator):
bl_idname = "scene.set_frame_10"
bl_label = "Set frame 10"
def execute(self, context):
main(context)
bpy.context.scene.frame_current = 10
return {'FINISHED'}
class TEST_PT_Panel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Set Frame"
bl_category = 'Item'
def draw(self, context):
self.layout.operator("scene.set_frame_10", text="Set frame 10")
def register():
bpy.utils.register_class(TEST_OT_setFrame10)
bpy.utils.register_class(TEST_PT_Panel)
def unregister():
bpy.utils.unregister_class(TEST_OT_setFrame10)
bpy.utils.unregister_class(TEST_PT_Panel)
if __name__ == "__main__":
register()
If I wanted to have such a button visible at startup without requiring to run it manually, I can either save it in the startup file and enable automatically runninf python files which is quite a security threat, or I must turn it into an addon.
Now the code looks like this:
bl_info = {
"name": "Set Frame 10",
"author": "Me",
"version": (1, 0),
"blender": (3, 3, 0),
"location": "View3D > Sidebar > Sef Frame",
"description": "Jump to frame 10",
"warning": "",
"doc_url": "",
"category": "Animation",
}
import bpy
class TEST_OT_setFrame10(bpy.types.Operator):
bl_idname = "scene.set_frame_10"
bl_label = "Set frame 10"
def execute(self, context):
main(context)
bpy.context.scene.frame_current = 10
return {'FINISHED'}
class TEST_PT_Panel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Set Frame"
bl_category = 'Item'
def draw(self, context):
self.layout.operator("scene.set_frame_10", text="Set frame 10")
def register():
bpy.utils.register_class(TEST_OT_setFrame10)
bpy.utils.register_class(TEST_PT_Panel)
def unregister():
bpy.utils.unregister_class(TEST_OT_setFrame10)
bpy.utils.unregister_class(TEST_PT_Panel)
if __name__ == "__main__":
register()
Also, it’s easy to forget this when we know programming, but because bpy forces the user to use functions and classes very quickly for anything, it quite significantly raises the entry level for doing anything. Comparing to Maya where you can run a simple command very easilly, here you have to manage contexts, changing syntax and access violations.
Make a button without an addon
In Blender
You simply cant do that easily and safely.
If you want a custom button for custom things, the only way to do it is to learn Python and BPY and make yourself an addon, or waste time making long scripts and run them manually, or store them in file and enable auto script run which shouldn’t be required.
Making addons is fine, but two issues here: it’s trickier and time-consuming, even for people who know programming on Blender, and it’s not user-friendly. I mean, that solution is basically as saying “Blender has no solution, make it yourself”.
In Maya
Maya has a shelf where anyone can create buttons that can do different things. That’s where addon developers usually put buttons for their addons, kind of Blender’s viewport sidebar.
But more interesting for this topic: that’s where users create their own buttons, containing macros and “anything they often use”.
I.E. as an animator, I often have different cameras to switch to while working, so I made buttons that switch the active viewport to specific cameras. I also made buttons that essentially act as viewport presets to quickly switch certain things on and off in one click. All this never required me to make an addon, nor operators, nor manage registrations, nor nothing. Just plain “do this” in python or Mel (Maya’s native scripting language).
But back to my example: If I wanted to make such a shelf button that jumps to frame 10, here are the steps anyone knowing maya python would do:
- open the script editor
- write:
import maya.cmds as cmds
cmds.currentTime(10,edit=True)
- select all, and MMB drag it to the shelf
Now I have a shelf button that makes Maya jump to frame 10:
Let’s make it even harder: let’s pretend that I don’t know any programming, and thus need first to discover what code does the thing I want in a button:
-
open the script editor, which also have a console that shows everything Maya does in Mel (maya’s native language):
-
set the current frame to 10 with the UI
-
copy what showed up in the script editor: currentTime 10;
-
MMB drag the selection to the shelf
I have now a button that makes Maya jump to frame 10 without ever needing to learn programming:
This illustrates another thing that Maya does nicely and I wish Blender did better:
Discoverability of scripting
Maya does a spectacular job at showing you how to make it do anything via scripts.
Blender does show up some things you do in the Info editor, but it shows so few things! Meanwhile in Maya:
Everything you do (every event from running a function to just opening a header menu), and even everything the program or an addon does, is prompted as Mel in the console. So that if you want to learn how to script anything in Maya, you can first do the thing with the UI and the Script Editor shows you exactly how it’s done in script.
Even if you are not a programmer and don’t intend to be, you can make so many things from macros to viewport presets to importing a character asset extremely easily thanks to this Script Editor that prompts everything and the toolshelf system that makes creating user content a child’s game.
A user completely scripting-agnostic can for example make a button that exports a selection of objects with a specific set of export options by just doing it once, then select-dragging what showed up in the console to the shelf.
That’s an insane level of user-friendlyness compared to Blender’s current state of “learn python and bpy and make an addon”, and for proof: almost everyone I know at work have such user made shelf buttons for anything they like, even though maybe five percent of them actually knows any scripting.
I’d also like to point out that the API’s doc is also IMHO slightly more helpful.
Taking the example of the currentTime
command. Here is the python doc of it:
currentTime command (python)
What I love in Maya’s api docs is that you alsways find cool usage examples for almost everything. I can’t imagine the time spent for writing examples for even the most trivial of things, but man that helps so much!
Making custom keyboard shortcut
In Maya
I open the Hotkeys Editor:
On the right I can create “runtime commands”. Containing the simplest scripts to full plugins.
On the right, i can see any runtime command I created and assign a hotkey of my chosing.
On Blender
You can’t do it as is.
Again, I must first create an operator, then encapsulate it in an addon if I want to always have it present in a safe manner at startup, then I can set a custom hotkey from Blender’s keymap preferences. Or assign the hotkey from the script which is its own diffiulty.