Autodesk 3ds Max ships with a pre-built version of PySide 2.0 compatible with Python 2.7.6. This version includes all standard PySide modules.
The following simple example shows how to obtain a handle for the PySide application object and create a widget:
'''
Demonstrates how to create a QWidget with PySide and attach it to the 3dsmax main window.
'''
from PySide import QtGui
import MaxPlus
class _GCProtector(object):
widgets = []
def make_cylinder():
obj = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.Cylinder)
obj.ParameterBlock.Radius.Value = 10.0
obj.ParameterBlock.Height.Value = 30.0
node = MaxPlus.Factory.CreateNode(obj)
time = MaxPlus.Core.GetCurrentTime()
MaxPlus.ViewportManager.RedrawViews(time)
return
app = QtGui.QApplication.instance()
if not app:
app = QtGui.QApplication([])
def main():
MaxPlus.FileManager.Reset(True)
w = QtGui.QWidget(MaxPlus.GetQMaxWindow())
_GCProtector.widgets.append( w )
w.resize(250, 100)
w.setWindowTitle('PySide Qt Window')
main_layout = QtGui.QVBoxLayout()
label = QtGui.QLabel("Click button to create a cylinder in the scene")
main_layout.addWidget(label)
cylinder_btn = QtGui.QPushButton("Cylinder")
cylinder_btn.clicked.connect(make_cylinder)
main_layout.addWidget(cylinder_btn)
textEdit = QtGui.QLineEdit()
textEdit.setText("Edit box")
main_layout.addWidget(textEdit)
w.setLayout( main_layout )
w.show()
if __name__ == '__main__':
main()
Notes:
Normally one creates a PySide application object in a script using QtGui.QApplication(). However, in 3ds Max, there is already a PySide application running, so you get a handle for that object like this:
QtGui.QApplication.instance()
Nodes created within a script may not appear in Max until the script exits, unless you force a viewport update. You can do so with MaxPlus.ViewportManager.ForceCompleteRedraw() or MaxPlus.ViewportManager.RedrawViews().
MaxPlus provides a facility for loading UI files created by Qt Designer: MaxPlus.LoadUiType(). For example (from demoPySideLoader.py):
import MaxPlus
import os
from PySide2.QtWidgets import QTabWidget
class TestWidget(QTabWidget):
def __init__(self, ui_class, parent=None):
QTabWidget.__init__(self, parent)
self.ui= ui_class()
self.ui.setupUi(self)
def test_load_ascii_ui_path(ui_path):
ui_class, base_class = MaxPlus.LoadUiType(ui_path)
instance = TestWidget(ui_class)
instance.show()
instance.close()
def test_load_ui():
ui_path = os.path.join(os.path.dirname(__file__), "test_ui.ui")
test_load_ascii_ui_path(ui_path)
# test unicode encoding
test_load_ascii_ui_path(u'%s' % ui_path)
# test a unicode encoding with non-ascii characters
try:
test_load_ascii_ui_path(u'D:/你好')
except UnicodeEncodeError:
pass
else:
print "Error: unexpected exception"
if __name__ == "__main__":
test_load_ui()