Maya Python read and set optionMenu value via variable - python

I have a module that creates a savedSettings.py file after the user used my tool this file is filled with variables to load into the gui next time the tool is used.
I have some checkboxes and a optionMenu. Reading and setting the variables for the checkboxes is as simple as:
# loadsettings into gui
if os.path.exists(userSettings):
sys.path.append(toolFolder)
import savedSettings
viewCBvalue = savedSettings.viewCheck
ornamentCBvalue = savedSettings.ornamentCheck
renderCBvalue = savedSettings.renderCheck
I thought the optionMenu would be the same and wrote:
encodingOMvalue = savedSettings.encodingCheck
When I now tell the GUI to use the variables:
cmds.checkBoxGrp( 'viewCB', label = 'View: ', value1 = viewCBvalue)
cmds.checkBoxGrp( 'ornamentCB', label = 'Show Ornaments: ', value1 = ornamentCBvalue)
cmds.checkBoxGrp( 'renderCB', label = 'Render offscreen: ', value1 = renderCBvalue)
cmds.optionMenuGrp( 'encodingOM', label = 'Encoding ', value = encodingOMvalue )
cmds.menuItem( 'tif', label = 'tif')
cmds.menuItem( 'jpg', label = 'jpg')
cmds.menuItem( 'png', label = 'png')
I get the follwing error:
RuntimeError: Item not found: tif #
My savedSettings.py looks like this:
# User Settings Savefile:
viewCheck = False
ornamentCheck = False
renderCheck = False
encodingCheck = "tif"
Would be great if someone explains me what I am doing wrong and how to set variables for the optionMenu.
Thanks for taking the time in advance and have a nice day coding!

Don't do this. instead use mayas internal mechanism, optionVar, for this.
But if you must do this then know that when you do:
import savedSettings
whatever is defined in savedSettings is stored inside savedSettings so if you have the var viewCBvalue then you call it with savedSettings.viewCBvalue. You could load this into main by calling import savedSettings as *, but you really, really do not want to do this!
Python import is not a normal function, results get cached.
Various other problems. Dont use import for this purpose
If you do not want to use optionVar, consider using pickle

Related

Button command doesn't updates my Label textvariable

I have this very easy program which I want to display one random line from a file each time I click on the Button.
Problem is a new line is display at startup of the program, but nothing happens when I click the button, can someone explain me why ?
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
fen = Tk()
fen.title("lexique anglais politique")
defi = StringVar()
defi.set(entree())
lab = Label(fen, textvariable=defi).pack()
Button(fen, text='Beste Bat', command=entree).pack()
fen.mainloop()
As stated in one of the comments (by #matszwecja), your entree() function doesn't really do anything appart from returning a value.
Nothing in your code updates the actual label. Try something like this :
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
def update_label():
lab.config(text=entree())
fen = Tk()
fen.title("lexique anglais politique")
lab = Label(fen, text=entree())
lab.pack()
Button(fen, text='Beste Bat', command=update_label).pack()
fen.mainloop()
In this example, the entree() function is used to go get a line from your file, and the update_label() function is used to actually update the label.
Also, if you want to be able to update a label, you'll have to pack it after assigning it to a variable.
On a side note, it could be worth noting that hardcoding values that could change in the future is generally considered bad practice. In that regard, I think coding the entree() function this way might be a better idea :
def entree():
fs = open('lexique','r')
liste = fs.readlines()
n=randrange(len(liste))
return liste[n]
This way, if you ever add or remove lines to your "lexique" file, you will not have to change the code.

Best way to pass initialized constants

I'm going to make an easy example on an application case of mine.
I am developing a gui with tkinter, my work is divided in 3 files:
constants:
CostoMedioEnergia = float(0.2) #
IncentivoAutFisico_Prop_Impianti = float(0.2)#
IncentivoAutFisico_DirittoSup = float(0.06)#
IncentivoAutFisico_Finanziatore = float(0.140)#
CostoFotovoltaico = float(1000)
ProduzioneFotovoltaico = float(1300) ##########
IncentivoRitDedicato = float(0.045)#
IncentivoMise = float(0.110)#
IncentivoArera = float(0.009)#
another file where I have the prototypes of the classes of users (here an example):
class ProprietarioImpianti(Parametri):
def __init__(self, ConsumiPrevisti, PotenzaContatore, PotenzaFotovoltaicoInstallato, PercEnerAutoconsumo, PercIncentivoAutconsumo, PercEnerCondivisa, PercMise, PercArera, PercIncentivoRitDedicato, IndiceUtente):
self.ConsumiPrevisti = ConsumiPrevisti
self.PotenzaContatore = PotenzaContatore
self.PotenzaFotovoltaicoInstallato = PotenzaFotovoltaicoInstallato
self.PercEnerCondivisa = PercEnerCondivisa #Energia in autoconsumo condiviso (percentuale sull'energia totale disponibile alla condivisione)
self.PercMise = PercMise #Percentuale incentivo Mise attributita all'utente
self.PercArera = PercArera # Percentuale incentivo Arera attribuita all'utente
self.PercEnerAutoconsumo = PercEnerAutoconsumo #Percentuale dell'energia prodotta che viene autoconsumata fisicamente
self.PercIncentivoAutoconsumo = PercIncentivoAutconsumo #Percentuale dell'incentivo autoconsumo attribuito all'utente
self.PercIncentivoRitDedicato = PercIncentivoRitDedicato
self.IndiceUtente = IndiceUtente
#property
def CostoMedioBolletta(self):
return self.ConsumiPrevisti * self.PotenzaContatore * CostoMedioEnergia
As you can see in the last line I'm using "CostoMedioEnergia" which is a constant imported from the previous file. The third and last file is my tkinter gui, you don't necessary need that, where I input some data and instantiate classes accordingly.
My question is: I want to input those constant data from the first file (such as CostoMedioEnergia) form the GUI in tkinter. What would be the best way to update my code so that I can use parameters form input? I thought to create a new class in the second file I mentioned (where all my other classes are) and to use inheritance. But this way I'd add a lot of attributes to my classes when I only need to store that information once and make it accessible to all classes without creating "copies" of the information in my "subclasses".

.set in function is not being found in other function so it's creating an error tkinter python

I'm trying to create a GUI, in the nav menu you can click a cascade option to open another window where you can click roll to generate a set of numbers. It comes up with error. I think it's because the function is called from another function I just don't know how to get that function to call it/ if there is any other ways to fix this. I've tried global functions and looking it up but haven't found anything other than using classes so far, which I don't know how to do.
line 147, in totalRolls
txtresultsOut.set(totalRollResults)
NameError: name 'txtresultsOut' is not defined
Here is the code that is relevant to it. I've called the function to skip having to input all the other code for the main gui window.
def rollSix():
s = 0
numbers = [0,0,0,0]
for i in range(1,5):
numbers[s] = randrange(1,7)
s += 1
numbers.remove(min(numbers))
Result = sum(numbers)
totalRollResults.append(Result)
def totalRolls():
rollOne()
rollTwo()
rollThree()
rollFour()
rollFive()
rollSix()
txtresultsOut.set(totalRollResults)
def rollw():
rollWindow = tix.Tk()
rollWindow.title("Dice Rolls")
diceLabel = Label(rollWindow, text = "Click Roll for your Stats")
diceLabel.grid(row = 0, column = 0)
rollBtn = Button(rollWindow, text = "Roll Stats", command = totalRolls)
rollBtn.grid(row = 1, column = 0)
txtresultsOut = StringVar()
resultsOut = Entry(rollWindow, state = "readonly", textvariable = txtresultsOut)
resultsOut.grid(row = 2, column = 0)
rollw()
first of all I would NOT recommend using StringVar(). You can use the .get() method of Entry to obtain the value inside the same. Try this way and make a global declaration of the Entry whose values you want to get in other functions.
EDIT------------
#you can use the following code to make your entry active to be edited.
entry.configure(state='normal')
# insert new values after deleting old ones (down below)
entry.delete(0,END)
entry.insert(0, text_should_be_here)
# and finally make its state readonly to not let the user mess with the entry
entry.configure(state='readonly')

maya python textField + object name Assistance Please

Here is my plan. First create a joint and open your node editor. When you got your joint created, name it "A_Joint" hit "load joint" after running the script, then hit "test" upon hitting test, you should get a node created with the name "A_Joint_firstGuy"
the objective of this script is to create a node based on the name of whatever you loaded into the textField. It will take the name of the selected object and add it to the front of the name of the node
Atleast thats what should happen, but in truth I lack the knowledge to figure this out and every google search has thus far been fruitless. The script is down below for anyone willing to take a crack at it, thank you for your time and I hope to hear back from you:
https://drive.google.com/file/d/1NvL0MZCDJcKAnVu6voVNYbaW0HurZ6Rh/view?usp=sharing
Or here, in SO format:
import maya.cmds as cmds
if cmds.window(window, exists =True):
cmds.deleteUI(window)
window = cmds.window(title = "DS Selection Loader Demo", widthHeight=(300, 200) )
cmds.columnLayout(adjustableColumn=True)
def sld_loadHelperJoint():
sel = cmds.ls(selection=True)
selString = " ".join(sel)
add = cmds.textField('sld_surfaceTextHJ', edit=True, text=selString)
#def sld_loadParentJoint():
# sel = cmds.ls(selection=True)
# selString = " ".join(sel)
# add = cmds.textField('sld_surfaceTextPJ', edit=True, text=selString)
def createNode():
testNode = cmds.createNode( 'transform', selString = "sld_surfaceTextHJ", name = '_firstGuy' )
cmds.columnLayout(adjustableColumn=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
cmds.button( label='Load Helper Joint', command = "sld_loadHelperJoint()")
cmds.setParent('..')
#cmds.columnLayout(adjustableColumn=True)
#name = cmds.textField('sld_surfaceTextPJ', width =240)
#cmds.button( label="Load Parent Joint", command = "sld_loadParentJoint()")
#cmds.setParent('..')
testNode = cmds.createNode( 'transform', name = textField +'_firstGuy' )
# you must first create "def" group for the attributes you
# want to be created via button, "testNode" is our example
# Connect the translation of two nodes together
#cmds.connectAttr( 'firstGuy.t', 'secondGuy.translate' )
# Connect the rotation of one node to the override colour
# of a second node.
#cmds.connectAttr( 'firstGuy.rotate', 'secondGuy.overrideColor' )
cmds.showWindow (window)
OK, there's a few things going on here to consider.
First, Maya gui widgets look like strings -- just like you make a polyCube and it comes back to you as the string 'pCube1', a widget will come back as a string like 'myWindow' or 'textField72'. Just like working with scene objects, you always need to capture the results of a command so you know what it's really called -- you can't guarantee you'll get the name you asked for, so always capture the results.
So you want to do something like this, just to get the graphics going:
window = cmds.window(title='selection loader demo')
column = cmds.columnLayout(adj=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
load_button = cmds.button( label='Load Helper Joint')
cmds.show_window(window)
If you needed to ask what's in the textField, for example, you'd do:
text_contents = cmds.textField(sld_textFld, q=True, text=True)
You notice that's with the variable, not the string, so we're sure we have whatever worked.
To make the button use that information, though, the button script needs to have access to the variable. There are several ways to do this -- it's a common stack overflow question -- but the easiest one is just to define the button command where you already have that variable. So the above sample becomes:
window = cmds.window(title='selection loader demo')
column = cmds.columnLayout(adj=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
def set_textfield(_):
sel = cmds.ls(selection=True)
add = cmds.textField(sld_textFld, edit=True, text=sel[0])
load_button = cmds.button( label='Load Helper Joint', c = set_textfield)
cmds.showWindow(window)
There are two bits here.
One is the _ in the function definition; Maya buttons always call their functions with one argument. There's nothing magical about the underscore, it's just Python slang for "ignore me" -- but if you don't have an argument in the function def, it will fail.
The more important bit is that the button is given the function definition directly, without quotes. You are saying call this function when clicked. If you use the string version -- a holdover from MEL -- you will run into problems later. The reasons are explained in detail here but the TLDR is don't use the the string form. Ever.
Now that the structural pieces are in place, you should be able to either the node creation to the function I called set_textfield() or make a second button\function combo that does the actual node creation, something like:
window = cmds.window(title='selection loader demo')
column = cmds.columnLayout(adj=True)
sld_textFld = cmds.textField('sld_surfaceTextHJ', width =240)
def set_textfield(_):
sel = cmds.ls(selection=True)
cmds.textField(sld_textFld, edit=True, text=sel[0])
load_button = cmds.button( label='Load Helper Joint', c = set_textfield)
def make_node(_):
text_value = cmds.textField(sld_textFld, q = True, text=True)
if text_value:
print "created:", cmds.createNode('transform', n=text_value +'_firstGuy')
else:
cmds.warning("select an object and add it to the window first!")
node_button = cmds.button( label='Make Node', c = make_node)
cmds.showWindow(window)

how to import my function to python file and get input from it?

I have a function called analyze() which is like following:
def analyze():
for stmt in irsb.statements:
if isinstance(stmt, pyvex.IRStmt.WrTmp):
wrtmp(stmt)
if isinstance(stmt, pyvex.IRStmt.Store):
address = stmt.addr
address1 = '{}'.format(address)[1:]
print address1
data = stmt.data
data1 = '{}'.format(data)[1:]
tmp3 = store64(address1, int64(data1))
if isinstance(stmt, pyvex.IRStmt.Put):
expr = stmt.expressions[0]
putoffset = stmt.offset
data = stmt.data
data4 = '{}'.format(data)[1:]
if (str(data).startswith("0x")):
#const_1 = ir.Constant(int64, data4)
tmp = put64(putoffset, ZERO_TAG)
else:
put64(putoffset, int64(data4))
if isinstance(stmt.data, pyvex.IRExpr.Const):
reg_name = irsb.arch.translate_register_name(stmt.offset, stmt.data.result_size(stmt.data.tag))
print reg_name
stmt.pp()
This code function gets following input and try to analyze it:
CODE = b"\xc1\xe0\x05"
irsb = pyvex.block.IRSB(CODE, 0x80482f0, archinfo.ArchAMD64())
When this input is in the same file in my code (lets call the whole as analyze.py) it works and python analyze.py will make me an output. However, I want to make a seperate file(call array.py), call analyze there and also put the inputs inside it and run python array.py to get the same result. I did the following for array.py:
from analyze import analyze
CODE = b"\xc1\xe0\x05"
irsb = pyvex.block.IRSB(CODE, 0x80482f0, archinfo.ArchAMD64())
analyze()
However, when I run the array.py, it stops me with error;
NameError: name 'CODE' is not defined
how can I resolve this problem? What is the solution?
A simple change in your function, add parameters:
def analyze(irsb): # irsb here called parameter
...
# The rest is the same
And then pass arguments when calling it:
from analyze import analyze
CODE = b"\xc1\xe0\x05"
irsb_as_arg = pyvex.block.IRSB(CODE, 0x80482f0, archinfo.ArchAMD64())
analyze(irsb_as_arg) # irsb_as_arg is an argument
I have just changed here irsb to irsb_as_arg to take attention, but it can be the same name

Categories