I have a python function here that is supposed to rename object in maya. But when the window showed up and i click the 'rename' button, nothing changed. not even bringing new window. please help
def renameObject():
a = cmds.ls(sl=True)
txt = cmds.textField('txtName', q=True, tx=True)
cmds.rename('a', txt)
cmds.confirmDialog(icn='information', message='Done!')
cmds.showWindow()
return
cmds.window(title='Rename Object')
cmds.columnLayout(adj=1)
cmds.text(label= 'Insert Name', w=300, h=30)
cmds.separator()
cmds.textField('txtName')
cmds.button(label='Rename', width=300, c=lambda*args:'renameObject()')
cmds.showWindow()
Two reasons:
Your lambda expression has a string 'renameObject()', it should be the function name without apostrope.
Even if the renameObject() function is called, it will fail because you assign the current selection to a variable called a. But in the rename function, you use again a string 'a'. So maya searches for an object called 'a' and tries to rename it what does not work unless you really have an object called 'a'.
And the confirmDialog() does not need a cmds.showWindow(), it works without.
def renameObject(*args):
a = cmds.ls(sl=True)
txt = cmds.textField(txt_field , q=True, tx=True)
cmds.rename(a[0], txt)
cmds.confirmDialog(icn='information', message='Done!')
cmds.showWindow()
cmds.window(title='Rename Object')
cmds.columnLayout(adj=1)
cmds.text(label= 'Insert Name', w=300, h=30)
cmds.separator()
txt_field = cmds.textField('txtName')
cmds.button(label='Rename', width=300, c=renameObject)
cmds.showWindow()
I've corrected your code, it shuold work when ran but there is lots of mistakes in your code, Haggi Krey has pointed lots of them. If you want to dive in UI design, you should look at partial module from functools. There is lots of examples here in Stack
Related
import maya.cmds as cmds
from functools import partial
def export(txtField):
print "hello"
#print cmds.textField( txtField, q=1 )
if cmds.window( 'exporter', q=1, ex=1 ):
cmds.deleteUI( 'exporter' )
window = cmds.window( 'exporter' )
cmds.columnLayout( adjustableColumn=True )
name = cmds.textField( text='testing...' )
press = cmds.button( 'Export...', c=partial( export, name) )
cmds.showWindow( 'exporter' )
So Im getting error:
# Error: export() takes exactly 1 argument (2 given) #
So Im new to partial and I dont understand what they do and how they work. But I know it's possible to do what I want with partial. So just print out whatever I have in textField
In this case partial is probably overkill. #mapofemergence's answer will work fine, but you can just do this:
from maya import cmds
if cmds.window('exporter', q=1, ex=1):
cmds.deleteUI('exporter')
window = cmds.window('exporter')
cmds.columnLayout(adjustableColumn=True)
tf = cmds.textField(text='testing...')
def export(*_):
print "textfield says" , cmds.textField(tf, q=1, text=1)
press = cmds.button('Export...', c=export)
cmds.showWindow('exporter')
since export is defined after the textfield is created, it captures the variable value at creation time.
Here's something which should work for you:
from maya import cmds
from functools import partial
def export(txtField, *args):
print txtField, ':', args
print cmds.textField(txtField, q=1, text=1)
if cmds.window('exporter', q=1, ex=1):
cmds.deleteUI('exporter')
window = cmds.window('exporter')
cmds.columnLayout(adjustableColumn=True)
name = cmds.textField(text='testing...')
press = cmds.button('Export...', c=partial(export, name))
cmds.showWindow('exporter')
What is happening (and might be confusing) is that the command invoked by Maya's button already passes an argument by default, in this case False. As a consequence, partial is appending the extra argument to the one you specified and therefore export is expected to receive two arguments, not just one.
It is quite some time I don't use native Maya UI commands, so I'm not sure what False stands for and if you can expect any meaningful argument to be passed, in different conditions.
Anyway, you can work around this by adding an extra argument to your function definition.
You could write something like def export(txtField, _): but that would only work if you're sure that the parameter being passed is one and only one. For that reason I used def export(txtField, *args): instead. This way you can print args and troubleshoot what's being passed (regardless the number of arguments), while having the rest of your code working.
As a side note, for other uses of partial with Maya you might want to read this:
https://theodox.github.io/2014/maya_callbacks_cheat_sheet
I have a Tkinter application, so I have the mainloop which is typical of Tkinter, and various functions which handle mouse clicks and all that garbage.
In one of the functions, I generate a string and I want to store that string SOMEWHERE in the program, so that I can use it later on if some other function is called or maybe if I want to print it from the main loop.
import this and that, from here and there etc etc
#blah blah global declarations
fruit = ''
def somefunction(event):
blahblahblah;
fruit = 'apples'
return fruit
mainwin = Tk()
#blah blah blah tkinter junk
#my code is here
#its super long so I don't want to upload it all
#all of this works, no errors or problems
#however
button = Button( blahblahblha)
button.bind("<button-1", somefunction)
print fruit
#yields nothing
mainwin.mainloop()
This is an abridged example. Everything else in the program works fine, I can track my variable throughout the program, but when it's time for it to be saved for later use, it gets erased.
For example, I can print the variable as I pass it along from one function to another as an argument, and it will be fine. It is always preserved, and prints. The instant I try to get it back into the loop or store it for later use, it gets lost or overwritten (I'm not quite sure which).
I am really unfamiliar with Python, so I bet it's something simple that I've missed. I am assuming this is supposed to work like every other language, where you save a string to a global variable, and it will stay there UNTIL you or something resets it or overwrites it.
My current workaround is to create a text file and save the string in it until I need it.
I am using Python 2.7.11 on Windows 7, but have had the same issue on Ubuntu.
When you do fruit = 'anything' inside the function, it assigns it as a local variable. When the function ends, that local variable disappears. If you want to reassign to a global variable, you need to indicate that you'd like to do so with the global keyword.
def somefunction(event):
global fruit # add this
blahblahblah
fruit = 'apples'
return fruit
Note that functions can access global variables without this line, but if you want an assignment to the same name to apply to the global one you have to include it.
Also, "<button-1" should be "<button-1>".
Also, instead of binding to a Button, you should just add a command to it:
button = Button(mainwin, text='blahblah', command=somefunction)
And Button widgets, when clicked, don't send an event object to the function they're bound to, so define somefunction as def somefunction():.
Also, the print fruit is executed exactly once. If you want to change fruit and then see the new value, you'll have to print it as some point after you've done the reassignment. Using return to send a value to a Button doesn't do anything, as the widget can't do anything with it. This is why Tkinter apps are commonly created as object-oriented (OO) programs, so you can easily save instance variables without having to use global.
Learn classes and your problems disappear. Almost any of these cover classes https://wiki.python.org/moin/BeginnersGuide/Programmers Also a Tkinter reference so you can fix your typos http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
class StoreVariable():
def __init__(self, root):
self.fruit = ''
button = tk.Button(root, bg="lightblue")
button.grid()
button.bind("<Button-1>", self.somefunction)
tk.Button(root, text="Exit", bg="orange", command=root.quit).grid(row=1)
def print_fruit(self):
print self.fruit
def somefunction(self, event):
self.fruit = 'apples'
print "fruit changed"
mainwin = tk.Tk()
SV=StoreVariable(mainwin)
mainwin.mainloop()
## assume that once Tkinter exits there is something stored
## note that you have exited Tkinter but the class instance still exists
print SV.fruit
## call the class's built in function
SV.print_fruit()
Basing on your abridged function, here are some things that might caused your problems:
You might not saved fruit to a variable inside the main loop/program. Values saved inside a function will be erased once that function finishes. Unless you saved it inside a class variable using self.variable_name (applicable if you are using classes). If you don't like classes, just save it within a variable inside the main loop/function like:
fruit = somefunction()
other stuff
print fruit #the time where you access fruit again
where this statement is inside the main loop/program where you would accesss it again with print.
You might be changing the value of fruit with other statements/functions. Not definite since you haven't posted your whole code.
For my job in a laboratory of my University of Applied Sciences I need to create a Python-programm which creates a child-windows with the possibility to create another one.
So far this works quite fine.
The tricky thing is where I close the childrens child and try to open a new "grandchild" of the main-window.
Closing and opening also works fine on the level of the first child. I can enter that child, go back to the main menu and so on as long I wish.
Here the code I am working on right now:
import tkinter
def Praktika():
global Praktika
Praktika = tkinter.Toplevel(main)
Praktika.geometry("320x200")
Prak1 = tkinter.Button(Praktika, text="Praktikum 1", command =Praktikum1)
Prak1.pack()
Haupt = tkinter.Button(Praktika, text="Hauptmenu", command = ClosePraktika)
Haupt.pack()
def ClosePraktika():
Praktika.destroy()
def Praktikum1():
global Praktikum1
Praktikum1 = tkinter.Toplevel(main)
Praktikum1.geometry("320x200")
Haupt = tkinter.Button(Praktikum1, text="Hauptmenu", command = ClosePraktikum1)
Haupt.pack()
def ClosePraktikum1():
Praktika.destroy()
Praktikum1.destroy()
def CloseAll():
main.quit()
main = tkinter.Tk()
main.geometry("320x200")
main.title("Fueh")
tkinter.Button(main, text="Praktika", command=Praktika).pack()
tkinter.Button(main, text="Exit", command=CloseAll).pack()
main.mainloop()
This is now the third attempt until now and ffter the research I have done I start to think that handling sub-children ain't that easy as I think.
So well,
already thank you very much for the help!
The problem is that you have a function named Praktikum1, and then you create a global variable named Praktikum1 which causes the function to be destroyed. So, the next time you call the function, you're actually "calling" the variable.
Don't use the same name for global variables and for functions.
folks! So, thanks to you guys I was able to figure out what it was I was doing wrong in my previous script of staggering animation for selected objects in a scene. I am now on part two of this little exercise: Creating a UI for it.
This involves creating a window with a button and user input of how much the animation will be staggered by. So, instead of me putting how much the stagger should increment by (which was two in my previous script), I'd now allow the user to decide.
The script I have so far created the window, button, and input correctly, though I am having some trouble with getting the UI to properly execute, meaning when I click on the button, no error pops up; in fact, nothing happens at all to change the scene. I get the feeling it's due to my not having my increment variable in the correct spot, or not utilizing it the right way, but I'm not sure where/how exactly to address it. Any help would be greatly appreciated.
The code I have (with suggested edits) is as follows:
import maya.cmds as cmds
spheres = cmds.ls(selection=True)
stagWin = cmds.window(title="Stagger Tool", wh=(300,100))
cmds.columnLayout()
button = cmds.button(label="My Life For Aiur!")
count = cmds.floatFieldGrp(fieldgroup, query=True, value=True)
fieldgroup = cmds.floatFieldGrp(numberOfFields=1)
cmds.button(button, edit=True, command=lambda _:stagger(fieldgroup))
cmds.showWindow(stagWin)
def stagger(fieldgroup):
for i in spheres:
cmds.selectKey(i)
cmds.keyframe(edit=True, relative=True, timeChange=count)
print "BLAH"
Moving the comments into an answer because I think I've got it all figured out finally:
First of all, the better practice is to pass the stagger object to the button command rather than the string. so that would be:
cmds.button(label="My Life For Aiur!", command=stagger)
Secondly, the count isn't getting updated, so it stays 0 as per your third line. To update that:
count = cmds.floatFieldGrp(fieldgroup, query=True, value=True)
But wait, where did fieldgroup come from? We need to pass it into the function. So go back to your button code and take out the command entirely, also saving the object to a variable:
button = cmds.button(label="My Life For Aiur!")
Now store the object for the fieldgroup when you make it:
fieldgroup = cmds.floatFieldGrp(numberOfFields=1)
Now that you have fieldgroup, you can pass that in the function for the button, like this:
cmds.button(button, edit=True, command=lambda _:stagger(fieldgroup))
I had to wrap the function in a lambda because we're passing fieldgroup, but if I just put stagger(fieldgroup) it would call that and pass the result of that into the command for the button
Also update stagger def with fieldgroup argument:
def stagger(fieldgroup):
One final note that won't actually affect this, but good to know:
when you shift the keyframes inside stagger you're using a DIFFERENT count variable than the one you declared as 0 up above. The outer one is global, and the inner is local scope. Generally it's best to avoid global in the first place, which fortunately for you means just taking out count = 0
Putting that all together:
import maya.cmds as cmds
spheres = cmds.ls(selection=True)
stagWin = cmds.window(title="Stagger Tool", wh=(300,100))
cmds.columnLayout()
button = cmds.button(label="My Life For Aiur!")
fieldgroup = cmds.floatFieldGrp(numberOfFields=1)
cmds.button(button, edit=True, command=lambda _:stagger(fieldgroup))
cmds.showWindow(stagWin)
def stagger(fieldgroup):
count = 0
increment = cmds.floatFieldGrp(fieldgroup, query=True, value=True)[0]
print count
for i in spheres:
cmds.selectKey(i)
cmds.keyframe(edit=True, relative=True, timeChange=count)
count += increment
print "BLAH"
I'm trying to dynamically create a RECENT FILES menu from a list, then use a common function to process the selected file.
Windows 7, Python 2.7
I can successfully create the menu, but haven't been able to find a way to pass an indicator to the common function to identify the user's selection. I keep slamming up against Python's pass-by-reference; no matter what I try, the last menu argument value created is passed to the command function.
I've searched extensively, and nothing I've found has helped. (I ALMOST got it working with an 'exec', but I'm doing this processing inside a class and 'exec' doesn't seem to like self. functions)
I don't care what I can get - an index, a file name, ANYTHING I can use to determine which entry has been selected. If I'm completely off track with my approach, PLEASE point me elsewhere. I'm a Python newbie, but a veteran programmer and would truly appreciate constructive guidance/ criticism.
Here's my last attempt, which simply demonstrates my problem. Everything I've tried has the same result - only ever returning the last list iteration:
from Tkinter import *
def processFile(fileIndex):
print fileIndex
file_list = [('01','File01'),('02','File02'),('03','File03')]
root = Tk()
menu_bar = Menu(root)
file_menu = Menu(menu_bar)
recent_menu = Menu(file_menu)
Menu(file_menu)
for i, file in enumerate(file_list):
file_display = '%d %s' % (int(file[0]), file[1]) # Just making the menu pretty
recent_menu.add_command(label=file_display, command=lambda: processFile('%d' % i))
file_menu.add_cascade(label='Recent Files', menu=recent_menu)
menu_bar.add_cascade(label="File", menu=file_menu)
root.config(menu=menu_bar)
mainloop()
recent_menu.add_command(label=file_display, command=lambda i=i: processFile(i))
If you do not use the i=i, the lambda variable are evaluated at run time, in stead of declaration time. - This is default for lambda functions.