Script communication ; how to get textfield data from UI to external script

Script communication ; how to get textfield data from UI to external script

Anonymous
Not applicable
6,292 Views
10 Replies
Message 1 of 11

Script communication ; how to get textfield data from UI to external script

Anonymous
Not applicable

Hi, I've created a maya python UI for a multiple scripts that I've made. Usually they are quite simple, a button will trigger a :

import sampleScript
reload (sampleScript)

but now i have a browse function on my UI that has a textfield data. I want my sampleScript to read this data. How do I structure my code so that my external sampleScript can read this data from my UI? 

the textfield are pymel objects. 

0 Likes
Accepted solutions (1)
6,293 Views
10 Replies
Replies (10)
Message 2 of 11

Anonymous
Not applicable

Are you using OOP (classes, objects, object oriented?) or not?

Are you using maya cmds or PySide or PyQt for the UI?

Is the creation of your field inside a function or outside it in the root of the file?

 

In case it's OOP: I suppose your tool is a class, so create an instance of your tool and add a method in that class to gather that data. The field must be an attribute of the class to access it through a instance.field way... there's a lot to ask about what you know here.

In case your tool is created inside the script but with no OOP, You shouldn't access internal UI of that tool from outside. Create a function for that and call it through sampleScript.gatherValue() or something like that.

 

If you don't have a function and all is in the root of the file (no identation), you should have a global variable in your script for that field:

 

variable = cmds.textField(...)

 

That variable, obviously, stores the hierarchy address of that field in the UI  (window|layout|bla|bla|bla...|field)

 

And then access that value through:   

 

cmds.textField(sampleScript.variable, query=True, value=True)

 

But this is a very bad solution for that. I really need more info about your code to understand what you need. I don't know what you know, either. 🙂

 

 

 

Message 3 of 11

Anonymous
Not applicable

Are you using OOP (classes, objects, object oriented?) or not?:

Yes my UI is a class.
Are you using maya cmds or PySide or PyQt for the UI?:
i'm using pymel objects.
Is the creation of your field inside a function or outside it in the root of the file? :
my textfield is inside my def __init__ function. 

it is :

self.unityPath = pm.textField(parent = self.rowco25,width = 240)

 

So you are saying i should create something like this in my UI class ? :
def gathertextfield(self, textfield):

    filepath = textfield.getText()

    return filepath

 

?? Am i on the right track? 

if so, how will my SampleScript , which exists outside my UI class , get this data? 

 

 

 

0 Likes
Message 4 of 11

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

Is it possible for your script to have the info when you've created the textfield? Maybe use MQtUtils to find your window and get the text from Qt directly is possible.

 

Could you post a sample here? A simple demo code will help us to understand how you script works.

 

Yours,

Li

0 Likes
Message 5 of 11

Anonymous
Not applicable

ya sure sorry it took so long, but i had to try and snip my code to something more manageable the first code is my UI code. 

import maya.cmds as cmds
import pymel.core as pm


class UIMain():
    
    
    def __init__(self, parent=None):
        
        self.winName = 'PR_Animhub'
        if pm.window(self.winName, exists=True):
            pm.deleteUI(self.winName)
        if pm.dockControl("animHubDock", label = "TIP_Animhub", exists = True) == True:
            pm.deleteUI("animHubDock")    
        pm.window(self.winName,  w=200,h=300,mnb=True,mxb=False,sizeable=True,resizeToFitChildren=True)
        pm.showWindow(self.winName)
        
        #blabla this middle part is not important .
        #below is the unity path checkbox 
                
        #main Layout start
        self.mainLay = pm.columnLayout(adjustableColumn=True)
        
        #End layout start
        self.endframe01 = pm.frameLayout(parent=self.mainLay,label='End',cll=1,cl=False,mh=5)
        self.rowco25 = pm.rowColumnLayout(parent=self.endframe01,numberOfColumns=5,height = 100,columnAttach=[1,'left',5])
        self.servChkbox = pm.checkBox(parent=self.rowco25,label = 'Server location', value = True ) 
        self.serverPath = pm.textField(parent = self.rowco25,width = 240,text = 'R:/Prototype/characters')
        pm.separator(parent=self.rowco25,width = 10,visible=False)
        self.serverBrowse = pm.button(parent=self.rowco25, label = ". . .", command=pm.Callback(self.browseServFn))
        pm.text(label='  Server Char folder')
        #self.cleanupBtn = pm.button(parent = self.rowco25, label = 'AnimBake',command = pm.Callback(self.animBakeFn))
        self.unityChkbox = pm.checkBox(parent=self.rowco25,height = 25,label = 'Unity Location', value = True) 
        self.unityPath = pm.textField(parent = self.rowco25,width = 240,text = 'D:/[Project]/Assets/ArtistFolder/LFS/Models/Characters')
        pm.separator(parent=self.rowco25,width = 10,visible=False)
        self.unityBrowse = pm.button(parent=self.rowco25, height = 20,label = ". . .", command=pm.Callback(self.browseUnityFn))
        pm.text(label='  Local Unity Char folder')
        
        self.gmoviesChkbox = pm.checkBox(parent=self.rowco25,height = 25,label = 'GDrive Movies', value = True) 
        self.gmoviesPath = pm.textField(parent = self.rowco25,width = 240,text = 'D:/GoogleDrive/Character Anim Movies/Milestone 1')
        pm.separator(parent=self.rowco25,width = 10,visible=False)
        self.gmoviesBrowse = pm.button(parent=self.rowco25, height = 20,label = ". . .", command=pm.Callback(self.browseUnityFn))
        pm.text(label='  Gdrive Movies folder')
        
        pm.button(parent=self.rowco25, label = "AnimBake", command=pm.Callback(self.animBakeFn))

        #end layout end


    def browseServFn(self, *args):
        pathholder = pm.fileDialog2(caption = "Character Directory" , dialogStyle=2, fileMode = 2, okCaption = "Select")
        
        pm.textField(self.serverPath,edit = True, text = str(pathholder[0]))
        
    def browseUnityFn(self,*args):
        pathholder = pm.fileDialog2(caption = "Unity Character Directory" , dialogStyle=2, fileMode = 2, okCaption = "Select")
        pm.textField(self.unityPath,edit = True, text = str(pathholder[0]))    
      
        
    def animBakeFn(self, *args):

        
        try:
            reload(Redeye_FBXBaker)
        except:
            import Redeye_FBXBaker
            reload(Redeye_FBXBaker)
        
x=UIMain()          

and the next snip is my animation bake code. Basically It will bake the animation ready to use for Unity. The only issue is, I want my UI to pass a string to my "Redeye_FBXBaker" function. So we can copy the result of the playblasts / FBX files into multiple locations. 

import maya.cmds as cmds
import pymel.core as pm
import maya.mel as mel
import random
import os
import sys
import subprocess 

PLAYER = 'pl_'
MOB = 'mob_'
BOSS = 'bs_'
fbxFolder='FBX'
fbxExt='.fbx'



def listCtrls():
    '''
    the usual list selection
    '''
    if len(cmds.ls(selection=True)) == 0  :
        cmds.confirmDialog(title='Selection Error',message='\n'+'You should select something',button = 'Ok',messageAlign='left',icon = 'warning')
    if len(cmds.ls(selection=True)) > 1  :
        cmds.confirmDialog(title='Selection Error',message='\n'+'You should select one thing',button = 'Ok',messageAlign='left',icon = 'warning')
    elif len(cmds.ls(selection=True)) == 1:
        return cmds.ls(selection=True)

def filenameManager():
    '''
    eg for character file D:/[Project]/Unnamed/scenes/pl_dod/01_original/pl_dod01_original_flinch_02.ma
    output 
    [0] filepath : D:/[Project]/Unnamed/scenes/pl_dod/01_original
    [1] fbx export filename  : pl_dod01_original@flinch
    [2] file extension : ma
    [3] iteration : 02
    [4] characterName
    [5] playblast local folder  : 
    [6] characterFolder : pl_dod 
    [7] characterVersion : 01_original
    '''
    
    filename=os.path.basename(pm.system.sceneName())
    fileExt=os.path.splitext(pm.system.sceneName())[1]
    fileloc=os.path.dirname(pm.system.sceneName())
    characterFolder = fileloc.split("/")
    print '#########################'
    
        
    for char in characterFolder :
        if "pl_" in char :
            print "this character is PLAYER"
            characterFolder = char
        if "bs_" in char :
            print "this character is BOSS"
            characterFolder = char
        if "mob_" in char :
            print "this character is MOB"
            characterFolder = char
    
    print 'Character is : %s' % characterFolder
    characterVersion = fileloc.split("/")[-1] 
    if "pl_" or "mob_" or "bs_" in characterVersion:
        characterVersion = "01_original"
        print 'Charcter Version : %s' % characterVersion

    fileIteration = filename.split(fileExt)[0].split("_")[-1]
    #knockout the iteration from filename.
    filenameList = filename.split(fileExt)[0].split("_")
    playblastName = '_'.join(filenameList)   
    del filenameList[-1]
    
    filenameList[2] = filenameList[2]+'@'+filenameList[3]
    del filenameList[-1]
    
    ExportFilename='_'.join(filenameList)
    
    #For playblast folder
    characterName=filename.split(fileExt)[0].split("_")[0]+'_'+filename.split(fileExt)[0].split("_")[1]
    #For playblast name
    

    return fileloc, ExportFilename, fileExt, fileIteration, characterName, playblastName , characterFolder, characterVersion

def makeDir(path):
    """
    input a path to check if it exists, if not, it creates all the path
    :return: path string
    """
    if not os.path.exists(path):
        os.makedirs(path)

def exportFBX(file1):
    try :
        return pm.system.exportSelected(file1[0]+'/'+fbxFolder+"/"+file1[1]+fbxExt, force = 1)
    except :
        print "fbx folder doesn't exist"
        makeDir(file1[0]+'/'+fbxFolder)
        return pm.system.exportSelected(file1[0]+'/'+fbxFolder+"/"+file1[1]+fbxExt,force = 1)


def _getPlaybackTimeRange():
    '''
    get playback time range
    '''
    AnimSt=cmds.playbackOptions( animationStartTime=True,query=True )
    AnimEnd= cmds.playbackOptions(animationEndTime=True,query=True )
    return AnimSt, AnimEnd


def _cleanupNamespace():
    '''
    find the reference, import it,
    finds the prefix of the reference and cleans up the namespace 
    '''
    for item in listCtrls():
        pre=str(listCtrls()[0])
        prefix = pre.rsplit(":")[0]
        print 'RIG is %s' % prefix
        ref=cmds.referenceQuery( item, filename=True )
        cmds.file(ref,importReference=True)
        cmds.namespace(mv=(prefix,":"),force=True)
        cmds.namespace(rm = prefix)
        print "namespace deleted and cleaned up"

def bakeJntMesh():
    #rest of bake fn
    allObjects = cmds.ls(l=True)
    jointsOnly=[]
    meshy=[]
    cmds.select(clear = True)
    
    for obj in allObjects:
       if cmds.nodeType(obj) == 'joint':
           jointsOnly.append(obj)
           cmds.setAttr((str(obj)+".segmentScaleCompensate"), 0)
    
    #cmds.bakeSimulation(jointsOnly, t=(AnimSt,AnimEnd),at=["rx","ry","rz","tx","ty","tz","sx","sy","sz"])
    cmds.bakeResults(jointsOnly,simulation=True, t=(_getPlaybackTimeRange()[0],_getPlaybackTimeRange()[1]),at=["rx","ry","rz","tx","ty","tz","sx","sy","sz"])
   
    cmds.select(clear = True)
    cmds.select(cmds.listRelatives(cmds.ls(type='mesh'),type='transform',p=True))
    cmds.bakeResults(t=(_getPlaybackTimeRange()[0],_getPlaybackTimeRange()[1]),at=["visibility"])
    #finish baking
    #now search for correct items and add it to your selction.
    cmds.select(clear = True)
    #check for model_root
    if cmds.objExists('model_root') == True :
        cmds.select('model_root')
        cmds.select(hi=True)
        cmds.select('model_root',d=True)
        cmds.select(jointsOnly,add=True)
        #cmds.confirmDialog(title='Success',message='\n'+'Bake Successful! Yay!',button = 'Ok',messageAlign='left',icon = 'information')
    
   
    else:
        cmds.confirmDialog(title='Selection Error',message='\n'+'model_root / model_root_fix doesnt exists',button = 'Ok',messageAlign='left',icon = 'warning')

def selectMainRef():
    cmds.select( clear=True )
    correctNode=[]
    allnurbs=cmds.listRelatives(cmds.ls(type='nurbsCurve'),p=True)
    for nurb in allnurbs:
        if str.lower(str(nurb.split(":")[-1])) == 'world_ctrl':
            cmds.select(nurb)      
    correctNode=cmds.ls(selection=True)
    return correctNode[0]
    

def muteWorld(world):
    cmds.currentTime(1)
    cmds.mute(str(world)+'.translateZ')
    cmds.mute(str(world)+'.translateX')
    cmds.mute(str(world)+'.translateY')        
        
        
def createPlayblast(filename1):
    
    #search for local movies folder
    #moviesFolder=pm.workspace(query=True, active=True)+'/movies/'+filename1[6]+'/'+filename1[7]+'/'
    moviesFolder=pm.workspace(query=True, active=True)+'/movies/'
    print moviesFolder
    panelnow=cmds.getPanel(wf=True)
    cmds.modelEditor(panelnow, e=1, displayLights='flat')
    thingstoHide = ['nurbsCurves', 'joints','motionTrails','locators','ikHandles']
    # for loop to check through all 4 items on top. 
    for thing in thingstoHide:
        kwargs = {'query': True, thing: True}
        thingCheck = cmds.modelEditor(panelnow, **kwargs)
        if thingCheck == True :
            kwargs = {'edit': True, thing: False}
            cmds.modelEditor(panelnow, **kwargs)
        else :
            print "%s is already hidden " % thing    
    return pm.playblast(format='qt',cc=True,filename=moviesFolder+filename1[5],fo=True,percent=100,compression='H.264',quality=100,width=960,height=540)
    #except :
        #cmds.confirmDialog(title='Error',message='\n'+'Playblast creation error+'\n, button = 'Ok',messageAlign='left',icon = 'information')

def mainBakefunction():
    '''
    compile all scripts bake all meshes and joints of related reference.
    clean up namespace
    
    '''
    file2=filenameManager()
    
    pbloc=createPlayblast(file2)
    muteWorld(selectMainRef())
    cmds.select( clear=True )
    selectMainRef()
    _cleanupNamespace()
    bakeJntMesh()
    fbxName = exportFBX(filenameManager())
    #cmds.confirmDialog(title='Success',message='\n'+'FBX Export Successful! Yay!'+'\n'+fbxName+'\n'+'Playblast Successful'+'\n'+ pbloc , button = 'Ok',messageAlign='left',icon = 'information')
    #tentatively integrated like crap here
    cmds.file(newFile=True,force=True)
    cmds.file(str(file2[0]+'/'+file2[5]+file2[2]), open=True)
    return file2[6],file2[7]

def grabDataFromUI():
    '''
    haven't figured out how to do this yet.
    '''

so... yeap. And if anyone has a good idea how to improve my script , your comments are appreciated. 

0 Likes
Message 6 of 11

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

If you could call your command inside ui would be simpler.

 

Or you could try to find the window with MQtUtil and get the text from Qt

 

import maya.OpenMaya as om
import maya.OpenMayaUI as omui

from PySide2.QtCore import * 
from PySide2.QtGui import * 
from PySide2.QtWidgets import *
from shiboken2 import *

qwidget = omui.MQtUtil.findControl("PR_Animhub")

if qwidget != None:
    window = wrapInstance(long(qwidget), QWidget) 
    edits = window.findChildren(QLineEdit)
    for edit in edits:
        print edit.text()

The textfields should be in order. Otherwise, you'll need to give them an object name.

 

Yours,

Li

0 Likes
Message 7 of 11

Anonymous
Not applicable

The thing is, I don't really know how to use Qt ... so um... i vaguely know i have to install pyqt and generate a UI then use my code to do callbacks on the ui components am i getting warm here? i thought pymel is already good enough =/ 

And the other thing is that i want to support parallel development , so if other people do some scripts, for their department i don't want them to touch the UI code and i'll sort of merge them in after i check the functionality they need. 

0 Likes
Message 8 of 11

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

Maya 2017/2018 is shipped with PySide2, so you don't have to install PyQt to get Qt support.

 

The sample code should be enough to iterating through the textfields in your window.

 

MEL is possible too. Using lsUI command to find all controls with long name and find textfields belongs to your window.

 

import maya.cmds as cmds

controls = cmds.lsUI(controls=True, long=True)
myWindowCtls = [ctl for ctl in controls if ctl.find('PR_Animhub') == 0]
myTextCtls = [ctl for ctl in myWindowCtls if ctl.find('textField') != -1]
fieldTexts = [(cmds.textField(text, query = True, pht=True), cmds.textField(text, query = True, text=True)) for text in myTextCtls]

print fieldTexts

I've put a placeholder text in your ui code for all textfields to help myself seperate different textfields.

 

Yours,

Li

 

 

0 Likes
Message 9 of 11

Anonymous
Not applicable

so basically i have to rewrite my code to work with pyQt ? Its just that my main purpose of asking is about how UIwindow and function codes can talk to each other despite being in different locations. Does this solve the problem?  
or should i just merge the my sample script with my UIwindow ?

0 Likes
Message 10 of 11

cheng_xi_li
Autodesk Support
Autodesk Support
Accepted solution

Hi,

 

Please read the post I've post earlier. It uses mel to query the textfields, e.g.

 

#Most of maya cmds are MEL commands in Python
import maya.cmds as cmds controls = cmds.lsUI(controls=True, long=True) myWindowCtls = [ctl for ctl in controls if ctl.find('PR_Animhub') == 0] myTextCtls = [ctl for ctl in myWindowCtls if ctl.find('textField') != -1] fieldTexts = [(cmds.textField(text, query = True, pht=True), cmds.textField(text, query = True, text=True)) for text in myTextCtls] print fieldTexts

 

It depends what you want to communicate between your class. Using Qt will give you direct access to the UI controls. If you are going to use QT, you could use pyside instead of pyqt.

 

Calling commands from UI directly would save definitely save some time.

 

Yours,

Li

0 Likes
Message 11 of 11

Anonymous
Not applicable

 

ah thanks i think i have an inkling how to do it. cheers

0 Likes