Qt Designer and Pyside Maya 2014

Hello all,

I’m trying to use the Qt Designer with Pyside in Maya 2014. Based on this link http://stackoverflow.com/questions/14892713/how-do-you-load-ui-files-onto-python-classes-with-pyside, I override the uiLoad, but I’m getting no result in loading a simple .ui file. Here’s my code :


from PySide import QtCore
from PySide import QtGui
from PySide.QtGui import QApplication, QMainWindow, QMessageBox

import main.pyside_dynamic as pdy

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        pdy.loadUi('E:/test.ui', self)
       
if __name__ == "__main__":
   MyMainWindow()

I would appreciate any help to get this working.

Thanks,
Vikram.

[QUOTE=floyd1510;22651]Hello all,

I’m trying to use the Qt Designer with Pyside in Maya 2014. Based on this link http://stackoverflow.com/questions/14892713/how-do-you-load-ui-files-onto-python-classes-with-pyside, I override the uiLoad, but I’m getting no result in loading a simple .ui file. Here’s my code :


from PySide import QtCore
from PySide import QtGui
from PySide.QtGui import QApplication, QMainWindow, QMessageBox

import main.pyside_dynamic as pdy

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        pdy.loadUi('E:/test.ui', self)
       
if __name__ == "__main__":
   MyMainWindow()

I would appreciate any help to get this working.

Thanks,
Vikram.[/QUOTE]

I’ve pretty much given up on getting loadui to work and have gone back to compiling to code with the uic crap. If PySide had better support, I would say that we should request PyQt like support for ui loading. Loading a pre-compiled .py is faster than dynamically loading a .ui anyway, so I might have gone this route regardless.

I think nathan horne wrote/ported a function for pyside that was similar in function to how pyqt does it. We used to do the compile to py, but iterating is a pain in the ass. With UI files, its way faster and less overhead.

From his site:

http://nathanhorne.com/?p=451

How to load a designer file

[ul]
[li]DO NOT USE cmds.loadUi!!![/li]> [LIST]
[li]seriously, don’t… forget it exists, now.[/li]> [li]Who ever wrote it needs to be punched in the mouth.[/li]> [/ul]

[li]Use uic/pysideuic (PySide has an alternate setup here), it’s awesome![/li]> [li]Note: pysideuic is lacking a loadUiType function, I have a workaround that I will try to mention in the example code. (Edit: here’s some PySide loadUiType code)[/li]> [li]The uic.loadUiType function is the one that should be used for loading in a PyQt UI from a designer file.[/li]> [li]Depending on how your resources are set up you may wish to alter the UI file before passing it to the loadUiType command. (See resources section below)[/li]> [/LIST]

[QUOTE=TheMaxx;22657]I think nathan horne wrote/ported a function for pyside that was similar in function to how pyqt does it. We used to do the compile to py, but iterating is a pain in the ass. With UI files, its way faster and less overhead.

From his site:

http://nathanhorne.com/?p=451[/QUOTE]

Yup. Been all down that path. I couldn’t ever get it to work reliably. Hopefully you’ll have a better experience.

What problems did you experience? Every so often i’ll hit a bug and have to dig into the exported py string to figure out what went wrong, but for the most parts it’s very smooth.

[QUOTE=TheMaxx;22662]What problems did you experience? Every so often i’ll hit a bug and have to dig into the exported py string to figure out what went wrong, but for the most parts it’s very smooth.[/QUOTE]

I could never get PyQt loadUIType to work correctly following this example: http://dl.dropboxusercontent.com/u/1633130/PyQt%20tuts/PySide_loadUiType.py. Perhaps it was something with the construction of our .ui files.

We use that one, but we added a bunch of things to the system path otherwise it couldn’t find some resource files or our subclasses. Once we added those, it’s been pretty solid

So I did replace the uiLoad with the one Nathan Horne mentioned, but still cannot get the ui window. His explanation is primarily for PyQt, but asks to use the pysideuic module for Pyside and the second thing I have changed is to use the shiboken module to get the Maya window. Here’s my code of Nathan’s PyQt example:

import pysideuic
import xml.etree.ElementTree as xml
from cStringIO import StringIO
from PySide import QtGui, QtCore
from shiboken import wrapInstance
import maya.OpenMayaUI as apiUI

def getMayaWindow():
    """
    Get the main Maya window as a QtGui.QMainWindow instance
    @return: QtGui.QMainWindow instance of the top level Maya windows
    """
    ptr = apiUI.MQtUtil.mainWindow()
    if ptr is not None:
        return wrapInstance(long(ptr),QtGui.QWidget)

def loadUiType(uiFile):
        """
        Pyside lacks the "loadUiType" command, so we have to convert the ui file to py code in-memory first
        and then execute it in a special frame to retrieve the form_class.
        """
        parsed = xml.parse(uiFile)
        widget_class = parsed.find('widget').get('class')
        form_class = parsed.find('class').text
    
        with open(uiFile, 'r') as f:
            o = StringIO()
            frame = {}
            
            pysideuic.compileUi(f, o, indent=0)
            pyc = compile(o.getvalue(), '<string>', 'exec')
            exec pyc in frame
            
            #Fetch the base_class and form class based on their type in the xml from designer
            form_class = frame['Ui_%s'%form_class]
            base_class = eval('QtGui.%s'%widget_class)
        return form_class, base_class 

#If you put the .ui file for this example elsewhere, just change this path.
listExample_form, listExample_base = loadUiType('E:/example1.ui')
class ListExample(listExample_form, listExample_base):
	def __init__(self, parent=getMayaWindow()):
		super(ListExample, self).__init__(parent)
		self.setupUi(self)

		#The names "addItemBtn" and "removeItemBtn"
		#come from the "objectName" attribute in Qt Designer
		#the attributes to access them are automatically created
		#for us when we call setupUi()
		#Designer ensures that the names are unique for us.
		self.addItemBtn.clicked.connect(self.addItem)
		self.removeItemBtn.clicked.connect(self.removeItem)

	def addItem(self):
		"""
		Add a new item to the end of the listWidget
		"""
		item = QtGui.QListWidgetItem(self.listWidget)
		item.setText('Item #%s!'%self.listWidget.count())

	def removeItem(self):
		"""
		Remove the last item from the listWidget
		"""
		count = self.listWidget.count()
		if count:
			self.listWidget.takeItem(count-1)

Here’s the .ui file (currently pointing to E:/example1.ui) :

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>399</width>
    <height>435</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="1" column="0">
     <widget class="QPushButton" name="addItemBtn">
      <property name="text">
       <string>Add Item</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="removeItemBtn">
      <property name="text">
       <string>Remove Item</string>
      </property>
     </widget>
    </item>
    <item row="1" column="2">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>40</width>
        <height>20</height>
       </size>
      </property>
     </spacer>
    </item>
    <item row="0" column="0" colspan="3">
     <widget class="QListWidget" name="listWidget"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>399</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

Thanks for the help,
Vikram.

I made a boilerplate which works either with PyQt or PySide (you set a variable to choose which one you want to use) in Maya, Nuke or as completely standalone. It should get you started:

I’m doing a blog post with some details on customizing it and I can post back the link when it’s published.

Hope it helps.

Hey Vikram,

So this is a work in progress, but it works with PySide. So I hope some of this code helps.

Create the .ui file
https://github.com/nicholas-silveira/art_pipeline/blob/master/dcc/packages/oop_dcc/tools/developer/ui/environment_tool.ui

Parse the .ui and get the main ui classes
https://github.com/nicholas-silveira/art_pipeline/blob/master/python/packages/oop_python/core/py_pyside.py

Get Maya window with PySide
https://github.com/nicholas-silveira/art_pipeline/blob/master/maya/packages/oop_maya/core/maya_window.py

Parent your ui to Maya
https://github.com/nicholas-silveira/art_pipeline/blob/master/dcc/packages/oop_dcc/tools/developer/environment_tool.py

-Nick

Please write the detail tutorial for use this 4 script to load .ui file use PySide, thanks

[QUOTE=Loading…;22756]Hey Vikram,

So this is a work in progress, but it works with PySide. So I hope some of this code helps.

Create the .ui file
https://github.com/nicholas-silveira/art_pipeline/blob/master/dcc/packages/oop_dcc/tools/developer/ui/environment_tool.ui

Parse the .ui and get the main ui classes
https://github.com/nicholas-silveira/art_pipeline/blob/master/python/packages/oop_python/core/py_pyside.py

Get Maya window with PySide
https://github.com/nicholas-silveira/art_pipeline/blob/master/maya/packages/oop_maya/core/maya_window.py

Parent your ui to Maya
https://github.com/nicholas-silveira/art_pipeline/blob/master/dcc/packages/oop_dcc/tools/developer/environment_tool.py

-Nick[/QUOTE]

hey guys, sorry for digging in old threads,

I picked up this code from a previous poster and tried to make it work.
And actually it works quiet well except when you click outside the gnerated window it will lose it’s focus and you can’t cancel it anymore or do anything.
Any idea how to wrap it to not lose focus?

pyside only of course since it’s supported by maya now, also I can’t have pyQt in our studio, we need to go out of the box due to whatever politics things.

that’s for the python code


import pysideuic
import xml.etree.ElementTree as xml
from cStringIO import StringIO
from PySide import QtGui, QtCore
from shiboken import wrapInstance
import maya.OpenMayaUI as apiUI
from pprint import pprint as pp



def getMayaWindow():
    """
    Get the main Maya window as a QtGui.QMainWindow instance
    @return: QtGui.QMainWindow instance of the top level Maya windows
    """
    ptr = apiUI.MQtUtil.mainWindow()
    if ptr is not None:
        return wrapInstance(long(ptr),QtGui.QWidget)

def loadUiType(uiFile):
        """
        Pyside lacks the "loadUiType" command, so we have to convert the ui file to py code in-memory first
        and then execute it in a special frame to retrieve the form_class.
        """
        parsed = xml.parse(uiFile)
        widget_class = parsed.find('widget').get('class')
        form_class = parsed.find('class').text
    
        with open(uiFile, 'r') as f:
            o = StringIO()
            frame = {}
            
            pysideuic.compileUi(f, o, indent=0)
            pyc = compile(o.getvalue(), '<string>', 'exec')
            exec pyc in frame
            
            #Fetch the base_class and form class based on their type in the xml from designer
            form_class = frame['Ui_%s'%form_class]
            base_class = eval('QtGui.%s'%widget_class)
        return form_class, base_class 




listExample_form, listExample_base = loadUiType('C://PATH_TO_YOUR_UI_FILE.ui')
class ListExample(listExample_form, listExample_base):
    def __init__(self, parent=getMayaWindow()):
        super(ListExample, self).__init__(parent)
        self.setupUi(self)



if __name__ == "__main__":
    le = ListExample()
    le.show()


and for qt designer ui file, just try with some empty design or something random test.

I’'d have to play with this code to see what it would take to make this support modal dialogs, but here’s a link since I’m not going to have time to play anytime soon.

http://doc.qt.io/qt-4.8/qdialog.html#modal-dialogs

im assuming its a dialog and its modal and it doens’t look like its parenting to maya correctly. your getMayaWindow() function could still return None thus not parenting to maya and just having a floating window. If that’s not the case, i’d have to see your ui file

[QUOTE=TheMaxx;28001]im assuming its a dialog and its modal and it doens’t look like its parenting to maya correctly. your getMayaWindow() function could still return None thus not parenting to maya and just having a floating window. If that’s not the case, i’d have to see your ui file[/QUOTE]

No idea what that modal or not modal does. I’m quiet new to using PySide, still learning.

this is an example ui file created with designer, just an empty window.
It happens to any kind of template or window you create in the designer, so the code that’s wrong is already within the python code so I guess it’s a wrapping problem.

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>399</width>
    <height>435</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="1" column="0">
     <widget class="QPushButton" name="addItemBtn">
      <property name="text">
       <string>Add Item</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="removeItemBtn">
      <property name="text">
       <string>Remove Item</string>
      </property>
     </widget>
    </item>
    <item row="1" column="2">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>40</width>
        <height>20</height>
       </size>
      </property>
     </spacer>
    </item>
    <item row="0" column="0" colspan="3">
     <widget class="QListWidget" name="listWidget"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>399</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

edit:
solved it, the window was not closed proberly.
I found some help here on tech-artists regarding win-event errors and found this to help me. Now it’s not losing focus anymore

if __name__ == "__main__":
    global win
    try:
        win.close()
    except:
        pass

    win = ListExample()
    win.setAttribute (QtCore.Qt.WA_DeleteOnClose)
    win.show()