I have designed a PySide interface for the 3D rendering software package Maya whose purpose is to take a file with animation on a single stream and break it up and export each range of animation. I'm pretty new to PySide and would like just a general overview (or harsh critique) of what I could do to improve the quality of this code. It's not entirely finished so some features of the UI don't actually hook up to anything yet such as the tpose box.
from PySide import QtGui, QtCore
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
import pymel.core as pm
import os
def mayaMainWindow():
mainWinPtr = omui.MQtUtil.mainWindow()
return wrapInstance(long(mainWinPtr), QtGui.QWidget)
class ExportBar(QtGui.QFrame):
def __init__(self, parent=None):
super(ExportBar, self).__init__(parent)
self.parent = parent
print parent.width(), parent.height()
self.resize(parent.width() - 30, 75)
self.widgets = [
QtGui.QLineEdit(),
QtGui.QSpinBox(),
QtGui.QLabel("-"),
QtGui.QSpinBox(),
QtGui.QPushButton(" Export "),
QtGui.QPushButton("Del")
]
self.widgets[1].setMaximum(pm.playbackOptions(max=1, q=1))
self.widgets[3].setMaximum(pm.playbackOptions(max=1, q=1))
self.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
self.setLineWidth(2)
self.initUI()
def initUI(self):
mainLO = QtGui.QHBoxLayout()
self.setLayout(mainLO)
self.widgets[0].setPlaceholderText("File Name")
self.widgets[-2].clicked.connect(lambda: exportAnimation(self))
self.widgets[-1].clicked.connect(self.deleteWidget)
for w in self.widgets:
mainLO.addWidget(w)
def deleteWidget(self):
self.parent.exportBars.remove(self)
self.close()
self.parent.holder.resize(self.parent.holder.width(), self.parent.holder.height() - self.height())
if self.parent.exportBars == []:
self.parent.cycleRow.newExportBar()
class FileBrowser(QtGui.QWidget):
def __init__(self, parent=None):
super(FileBrowser, self).__init__(parent)
self.parent = parent
self.resize(parent.width(), 20)
mainLO = QtGui.QHBoxLayout()
self.setLayout(mainLO)
mainLO.setSpacing(10)
self.pathBar = QtGui.QLineEdit(parent.workScenePath)
self.pathBar.textChanged.connect(self.changeWorkPath)
fileButton = QtGui.QPushButton("Browse Files")
fileButton.clicked.connect(self.changePath)
mainLO.addWidget(self.pathBar)
mainLO.addWidget(fileButton)
def changePath(self):
newPath = pm.fileDialog2(fileMode=3, okc="Select")
try:
self.pathBar.setText(newPath[0])
except Exception:
pass
def changeWorkPath(self):
self.parent.workScenePath = self.pathBar.text()
class CycleRow(QtGui.QWidget):
def __init__(self, parent=None):
super(CycleRow, self).__init__(parent)
self.resize(parent.width(), 20)
self.parent = parent
mainLO = QtGui.QHBoxLayout()
mainLO.setContentsMargins(0, 0, 0, 0)
mainLO.setSpacing(25)
mainLO.addSpacing(2)
self.setLayout(mainLO)
self.newExpBarButton = QtGui.QPushButton(" New Cycle List ")
self.newExpBarButton.clicked.connect(self.newExportBar)
self.tPoseFrameBox = QtGui.QSpinBox()
self.tPoseFrameBox.setContentsMargins(0, 0, 70, 0)
self.tPoseFrameBox.valueChanged.connect(self.changeTPoseFrame)
expAllButton = QtGui.QPushButton(" Export All ")
expAllButton.setContentsMargins(0, 0, 0, 0)
expAllButton.clicked.connect(lambda: exportAllAnimations(parent))
label = QtGui.QLabel("T Pose Frame")
label.setContentsMargins(0, 0, 0, 0)
mainLO.addWidget(label)
mainLO.addWidget(self.tPoseFrameBox)
mainLO.addWidget(self.newExpBarButton)
mainLO.addWidget(expAllButton)
def newExportBar(self):
exportBar = ExportBar(self.parent)
self.parent.holderLO.addWidget(exportBar)
self.parent.exportBars.append(exportBar)
self.parent.holder.resize(self.parent.holder.width(), self.parent.holder.height() + exportBar.height())
def changeTPoseFrame(self):
self.parent.tPoseFrame = self.tPoseFrameBox.text()
class AnimationCycleSplitter(QtGui.QWidget):
def __init__(self, parent=mayaMainWindow()):
super(AnimationCycleSplitter, self).__init__(parent)
self.workScenePath = os.path.join(pm.workspace.path, "scenes\\")
self.setWindowFlags(QtCore.Qt.Window)
self.setGeometry(300, 300, 600, 350)
self.setWindowTitle("Animation Cycle Splitter")
self.exportBars = []
self.initUI()
def initUI(self):
mainLO = QtGui.QVBoxLayout()
mainLO.setSpacing(10)
self.setLayout(mainLO)
browser = FileBrowser(self)
self.holder = QtGui.QWidget()
self.holder.resize(self.width() - 30, 0)
self.holderLO = QtGui.QVBoxLayout()
self.holderLO.setContentsMargins(0, 0, 0, 0)
self.holder.setLayout(self.holderLO)
scrollArea = QtGui.QScrollArea()
scrollArea.setWidget(self.holder)
self.cycleRow = CycleRow(self)
self.tPoseFrame = self.cycleRow.tPoseFrameBox.value()
self.cycleRow.newExportBar()
mainLO.addWidget(browser)
mainLO.addWidget(scrollArea)
mainLO.addWidget(self.cycleRow)
self.show()
class Keyframe(object):
def __init__(self, objs):
self._frame = pm.currentTime()
self._values = {attr:attr.get() for obj in objs for attr in obj.listAnimatable()}
self._objs = objs
def paste(self, frame):
pm.currentTime(frame)
for attr in self._values.keys():
try:
attr.set(self._values[attr])
except RuntimeError:
pass
pm.setKeyframe(self._objs)
def exportAllAnimations(gui, fileType=".ma"):
for ebar in gui.exportBars:
exportAnimation(ebar, fileType=fileType)
def getKeysForFramerange(beg, end, joints):
keys = []
for num, frame in enumerate(range(beg, end)):
pm.currentTime(frame)
keys.append(Keyframe(joints))
return keys
def pasteKeysForFramerange(keys):
for frame, key in enumerate(keys):
key.paste(frame)
def exportAnimation(gui, fileType=".ma"):
pm.currentTime(gui.tPoseFrame)
joints = pm.ls(type="joint")
tPose = [Keyframe(joint) for joint in joints]
pm.select(joints)
fullPathToFile = os.path.join(gui.parent.workScenePath, gui.widgets[0].text() + fileType)
beg, end = gui.widgets[1].value(), gui.widgets[3].value()
keys = getKeysForFramerange(beg, end, joints)
pm.copyKey()
pm.cutKey()
pasteKeysForFramerange(keys)
pm.currentTime(0)
pm.exportAll(fullPathToFile, force=1)
pm.pasteKey()