Maya Python multiple functions to one button - python

I am creating a rig through scripting and I have a UI. I would like to connect multiple functions to one button. Or rather, have a function inside of a function. Any suggestions on how to go about this issue?
I am importing the following libraries:
import maya.cmds as cmds
from functools import partial

Could you explain further more what you to do with a little example ?
I see you want to use partial so you may have multiple variables to pass through ?
My first idea would to create a function grouping your multiples function, ie :
def temp01():
return cmds.ls(sl=True)
def connection(obj01, obj02):
someCommand(obj01, obj02)
def printor():
print('yeah it is working')
def uiCommandButton_whatShouldIDoFunc(obj02, specialOkay, *args):
someCommand(temp01(), obj02)
specialOkay() #should print message
button01 = cmds.button(c=partial( uiCommandButton_whatShouldIDoFunc, cmds.ls(sl=1)[-1]), printor )

To have things nice and clean, I would use handlers.
A handler is a method that is called when an event occurs on your GUI element, like click. In the handler you can do whatever you want to (like calling your two functions). Handlers/event handlers are a tried and test GUI programming technique.
Here is an example:
my_button = cmds.button(command=partial(my_button_on_click_handler, arg1, arg2))
def my_button_on_click_handler(arg1, arg2):
# call all your functions and do stuff here
my_other_func1(arg1)
my_other_func2(arg2)
Some great posts on this topic (courtesy: #theodox and his awesome blog):
http://techartsurvival.blogspot.ca/2014/04/maya-callbacks-cheat-sheet.html?m=1
http://techartsurvival.blogspot.ca/2014/04/the-main-event-event-oriented.html?m=1

There is a "dirty" way of doing so by using PyMel and PySide/Qt.
First, turn your button into Pymel button :
import pymel.core as pm
import pymel.core.uitypes as pui
pyBtn = pm.button(label="", etc...)
or
pyBtn = pui.PyUI(my_button)
Then, convert it to a QtObject:
qtBtn = pyBtn.asQtObject()
And finally, you can add functions when the button is clicked like that:
qtBtn.clicked.connect(func1)
qtBtn.clicked.connect(partial(func2, arg1))
etc...
But like I said, this is not really recommended... It's just another way of doing it.
I thought it might be interesting to share it.
As an example, you can use this solution if the UI already exists, but you can't access the code that creates it.
Otherwise, I would do like suggested in the other answers, creating handlers functions.
PS : This will only works with maya2014 and above, or a maya with PyQt installed !

Related

Calling functions without making the script launch

The title isnt very accurate i think
Here are my script at the right
Screenshot
It's a bot to automatize some actions. Now i want to add some gui to it but i dont know how.
Like you see at the left, i have " import questions" but cuz of it when I launch the tkinter file, it automatically launches the questions without taking my openBtn code into account.
How can I add gui to each command of my questions.py?
You need to break your questions.py script into actual functions . Python will simply execute all actions in questions.py when the namespace is imported before it reaches the logic below the import statements in testkinter.py.
So in questions.py remove your while True: statements in favor of function definitions like:
def check_database(param):
database check logic here
Then link the functions defined in questions.py to Tkinter button actions in testkinter.py like this:
w = tkinter.Button( fenetre, command=check_database )

How do I reset a TraitsUI python application?

I am working on a Python program which performs various calculations. There are many different parameters that need to be inputed, and it can get confusing to remember what changes you made to the different inputs. I want to have a button that resets everything to their default values, so basically like restarting it, but without actually closing it/needing to run it again. I have used TraitsUI to design the GUI. How can I implement this ? I saw on the TraitsUI User manual that there is a reset command:
reset(destroy=True)
"Resets the contents of a user interface"
,but I don't actually know how and where to use this.
Here is a quick overview of how my code is formatted from start to end.
import os
os.environ['ETS_TOOLKIT'] = 'qt4'
os.environ['QT_API'] = 'pyqt'
from traits.api import HasTraits, Range, ...
...
class class1(HasTraits)
...
class class10(HasTraits)
mrm = class10()
mrm.configure_traits(kind='livemodal')
I have looked at this and this but they either didn't work or I just don't know to implement them properly in my program's layout. Looking forward to any advice/help.
I just read into this but look into reset_traits()
Try adding a "refresh" button to the GUI where
def _refresh_fired(self):
self.reset_traits()
This will reset all traits within your class. If you want to reset some of the traits, pass a list of strings along with it.
self.reset_traits(['trait1', 'trait2'])

Function not defined when Importing Maya Python Script

I have a tool I wrote in python that works completely fine when running in the maya script editor. However, I want to be able to import the script from the script directory. Which should be simple, and I am shocked I can't find the solution while searching the web.
My script format is like this example:
import maya.cmds as cmds
# GUI code with buttons, they call the functions below.
#
#
def function1():
#commands that do things
def function2():
#commands that do things
#List of functions continues
Like I said, the program functions perfectly when run in the script editor. When saving the script to the directory and using this method:
import module
reload (module)
module.function()
The GUI loads fine, but then when pushing the gui buttons, it says the functions are not defined. I don't understand what I am missing? If the script was loaded, shouldn't the functions be defined? Any help would be greatly appreciated, thank you!
Just because the GUI loads doesn't mean that all of your functions loaded properly. You need to put your file, (module.py) in a directory that is visible to your PYTHONPATH. If you're in Maya, you can also put it in the MAYA_SCRIPT_PATH
The PYTHONPATH / MAYA_SCRIPT_PATH are environment variables that you set before launching Maya. In a default Maya installation, some places where you could put your module.py file would be:
(Windows) C:\Users\YOUR_USER_NAME\Documents\maya\scripts
(Linux) ~/maya/scripts
(Mac) - Not sure, put probably also ~/maya/scripts
If you want to know where else you can place it, you run this
import os
print(os.getenv('MAYA_SCRIPT_PATH', ''))
print(os.getenv('PYTHONPATH', ''))
Any location in that list that you have write permissions to is OK to add your module.py file.
Also, it's worth noting that in your example module.function() would fail. It'd need to be module.function1() or module.function2() but I assume you know that. Hope this helps
Sup guys
So i know this is an old question that has already been answered but I have some extra information that helps in regards to GUI functions not working. (same error)
and there's basically nothing on this anywhere.
so the script director only helps when loading in the module through the shelf but will still return the same error "fuction is not defined"
this has todo with how the function is called through the UI element.
example.
this is will allow you to call function in the script editor
but gives you the function not defined error when the module is imported
def GUI_function():
pm.button( command = "function()")
def function():
do stuff
this on the other hand works.
def GUI_function():
pm.button( command = function)
def function(*_):
do stuff
i don't know why but maya tends to think function() is a nodetype
so remove the brackets if you not using arguments and you good to go

Trouble importing files in Python

I'm just finding out now that when importing a module, it seems to run through ALL the code, instead of just the one function that I want it to go through. I've been trying to find a way around this, but can't seem to get it. Here is what is happening.
#mainfile.py
from elsewhere import something_else
number = 0
def main():
print('What do you want to do? 1 - something else')
donow = input()
if donow == '1':
something_else()
while 1:
main()
#elsewhere.py
print('I dont know why this prints')
def something_else():
from mainfile import number
print('the variable number is',number)
Now, although this code KIND OF works the way I want it to, the first time when I initiate it, it will go to the main menu twice. For example: I start the program, press one, then it asks me what I want to do again. If I press one again, then it will print "the variable number is 0".
Once I get this working, I would like to be importing a lot of variables back and forth. The only issue is,if I add more import statements to "elsewhere.py" I think it will just initiate the program more and more. If I put "from mainfile import number" on line 1 of "elsewhere.py", I think this raises an error. Are there any workarounds to this? Can I make a different file? What if I made a class to store variables, if that is possible? I'm very new to programming, I would appreciate it if answers are easy to read for beginners. Thank you for the help.
As Jan notes, that's what import does. When you run import, it runs all of the code in the module. You might think: no it doesn't! What about the code inside something_else? That doesn't get run! Right, when the def statement is executed it creates a new function, but it doesn't run it. Basically, it saves the code for later.
The solution is that pretty much all interesting code should be in a function. There are a few cases which make sense to put at the top-level, but if in doubt, put it inside a function. In your particular case, you shouldn't be printing at the top level, if you need to print for some reason, put that into a function and call it when you need it. If you care when something happens, put it in a function.
On a second node, don't import your primary script in other scripts. I.e. if your mainfile.py directly, don't import that in other files. You can but it produces confusing results, and its really best to pretend that it doesn't work.
Don't try to import variables back and forth. Down that path lies only misery. You should only be importing things that don't change. Functions, classes, etc. In any other case, you'll have hard time making it do what you want.
If you want to move variables between places, you have other options:
Pass function arguments
Return values from a function
Use classes
I'll leave it is an exercise to the reader to learn how to do those things.
import executes imported code
import simply takes the Python source file and executes it. This is why it prints, because that instruction is in the code and with import all the instructions get exectued.
To prevent execution of part of imported package/module, you shall use the famous:
if __name__ == "__main__":
print("I do not print with `import`")
Note, that this behaviour is not new in Python 3, it works the same way in Python 2.x too.

running a method within another method. python

I am calling a method within another. and the error for this script i am getting is
NameError: name 'mnDialog' is not defined
Is there a reason for it? I think it has something to do with executing a command which isn't on the global level. (i didn't have the impression that python has a global and local variable declaration.) What is the right syntax or the go around this?
thank you for your time.
import maya.cmds as cmds
def mnProgRun():
def mnDialog(*args):
cmds.confirmDialog( title='Confirm', message='Are you sure?',button=['Yes','No'], defaultButton='Yes',cancelButton='No',dismissString='No' )
def mnMakeWin():
cmds.window( 'mnWin', title = 'testman', wh=(260,100))
cmds.columnLayout(adjustableColumn=False, columnAlign='center')
cmds.button( label="Yes,it works",align='center',width=120,height=25, backgroundColor=[0.5,1,0.5],command='cmds.scriptJob( event=["SelectionChanged","mnDialog"])')
cmds.button( label="No, Thank You!",align='center',width=120,height=25, backgroundColor=[1,0.5,0.5],command='cmds.deleteUI("mnWin")')
cmds.showWindow( 'mnWin' )
mnMakeWin()
mnProgRun()
The problem is that the mnDialog is not being looked up from mnMakeWin, you are passing the name and it gets looked up later when you are not in the correct scope.
It may work to pass the function in instead of the name. I don't have maya installed, so I can't try it.
Otherwise you'll have to define mnDialog in the global scope which seems like an odd restriction to me
mnDialog is a local variable in mnProgRun. It is not accessible outside the function scope. If you want it to be, define it at the appropriate scope.
(i didn't have the impression that python has a global and local variable declaration.)
You have the wrong impression.
You should define mnDialog at the top level. It is not in the correct namespace.
Also, it's (almost) always unnecessarily complicating to nest functions in Python.
maya always have problems with scoops,
you may define mnDialog() and mnMakeWin() outside the function, at the top scoop level,
its maya problem not from python, as i faced problem when calling class methods from maya ui command (ex button event).
hope that will help you :)
##edit
import maya.cmds as cmds
def mnDialog(*args):
cmds.confirmDialog( title='Confirm', message='Are you sure?',button=['Yes','No'],
defaultButton='Yes',cancelButton='No',dismissString='No' )
def mnMakeWin():
cmds.window( 'mnWin', title = 'testman', wh=(260,100))
cmds.columnLayout(adjustableColumn=False, columnAlign='center')
cmds.button( label="Yes,it works",align='center',width=120,height=25,
backgroundColor=[0.5,1,0.5],command='cmds.scriptJob( event=
["SelectionChanged","mnDialog"])')
cmds.button( label="No, Thank You!",align='center',width=120,height=25,
backgroundColor=[1,0.5,0.5],command='cmds.deleteUI("mnWin")')
cmds.showWindow( 'mnWin' )
def mnProgRun():
mnMakeWin()
#run
mnProgRun()

Categories