Maya 2017, Pyside 2, "wrapInstance"

So what’s the code to replace shiboken.wrapInstance in pyside2? google skills fail me this time. what’s the PySide2 equivalent for the below code?

from shiboken import wrapInstance 

mayaPtr = omui.MQtUtil.mainWindow() 
mayaWindow = wrapInstance(long(mayaPtr), QtGui.QWidget)

Hey Viktoras,
Small world :slight_smile:
Give that a whirl.
-Sean

try:
	from shiboken import wrapInstance
except:
	from shiboken2 import wrapInstance 

mayaPtr = omui.MQtUtil.mainWindow() 
mayaWindow = wrapInstance(long(mayaPtr), QtGui.QWidget)
1 Like

You’ll also need to account for QWidget no longer being part of QtGui, instead it belongs to a separated module QtWidgets. You’d import like so:

from PySide2 import QtWidgets

i have some snippets you can use to make sure it works for all Mayas that use QT, the loadUIType and wrapinstance are taken from Nathan Horne (http://nathanhorne.com), and so far most of it seems to work fine.
haven’t done extensive tests yet:

import logging
default = "none"
try:
    from PyQt4 import uic
    from PyQt4.QtCore import *
    from PyQt4.QtGui  import * 
    from PyQt4 import QtGui  
    import sip
    default = "pyqt4"
    logging.Logger.manager.loggerDict["PyQt4.uic.uiparser"].setLevel(logging.CRITICAL)
    logging.Logger.manager.loggerDict["PyQt4.uic.properties"].setLevel(logging.CRITICAL)
except: 
    try:
        import xml.etree.ElementTree as xml
        from cStringIO import StringIO
        import pysideuic, shiboken
        from PySide.QtGui  import * 
        from PySide.QtCore import *
        from PySide import QtGui
        default = "pyside"
        logging.Logger.manager.loggerDict["pysideuic.uiparser"].setLevel(logging.CRITICAL)
        logging.Logger.manager.loggerDict["pysideuic.properties"].setLevel(logging.CRITICAL)
    except:
        try:
            import xml.etree.ElementTree as xml
            from cStringIO import StringIO
            import shiboken2 as shiboken
            import pyside2uic as pysideuic
            from PySide2.QtGui     import * 
            from PySide2.QtCore    import *
            from PySide2.QtWidgets import *
            from PySide2 import QtGui
            default = "pyside2"
            logging.Logger.manager.loggerDict["pyside2uic.uiparser"].setLevel(logging.CRITICAL)
            logging.Logger.manager.loggerDict["pyside2uic.properties"].setLevel(logging.CRITICAL)
        except:
            print "PySide(2) and PyQt4 not found"

def loadUiType( uiFile ):
    if default ==  "pyqt4":
        form_class, base_class =  uic.loadUiType( uiFile )
    else:
        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

            form_class = frame[ 'Ui_%s'%form_class ]
            base_class = eval( '%s'%widget_class )
    return form_class, base_class

def wrapinstance( ptr, base=None ):
    if ptr is None:
        return None
    ptr = long( ptr ) 
    if globals().has_key( 'shiboken' ):
        if base is None:
            qObj = shiboken.wrapInstance( long( ptr ), QObject )
            metaObj = qObj.metaObject()
            cls = metaObj.className()
            superCls = metaObj.superClass().className()
            if hasattr( QtGui, cls ):
                base = getattr( QtGui, cls )
            elif hasattr( QtGui, superCls ):
                base = getattr( QtGui, superCls ) 
            else:
                base = QWidget
        return shiboken.wrapInstance( long( ptr ), base )
    elif globals().has_key( 'sip' ):
        base = QObject
        return sip.wrapinstance( long( ptr ), base )
    else:
        return None

there’s also this https://github.com/mottosso/Qt.py

1 Like

thanks all. As the main goal was to find Maya’s main window, went with:




try:
    from PySide import QtGui as widgets
except:
    from PySide2 import QtWidgets as widgets

#.. later

def mainWindow():
    for widget in widgets.qApp.topLevelWidgets():
        if widget.objectName()=='MayaWindow':
            return widget
    raise MessageException('QT Main window could not be detected')

Here’s one more.


from Qt import QtWidgets  # Any binding
main_window = dict([o.objectName(), o] for o in QtWidgets.qApp.topLevelWidgets())["MayaWindow"]

For Qt 4, replace QtWidgets with QtGui, or use Qt.py.

For Maya 2015 and above, you can use the tidier syntax.


from Qt import QtWidgets  # Any binding
main_window = {o.objectName(): o for o in QtWidgets.qApp.topLevelWidgets()}["MayaWindow"]

Edit: Ah! Just noticed you were doing exactly this in your latest post, uiron. +1 to you!

While a one-liner, it’s both less-readable and less eficient, won’t you agree?

I guess something like below is acceptable as you’re at most building a list of one item.


main_window = [o for o in QtWidgets.qApp.topLevelWidgets() if o.objectName()=="MayaWindow"][0]

…but from my experience, the more verbose syntax always wins the readability battle. for-lopp with an if-statement reads as “i’m going through all items, looking for entry with particular name”. One-liner way says “I’m building this list of all names then keeping just the first one, because I know there will be only one and exactly the one I need”.

> While a one-liner, it’s both less-readable and less eficient, won’t you agree?

I can see it both ways. I have no preference, it was just how I was used to seeing and typing it. Your example is equal to me.

Just for the record, I wrote an article a while ago about all this in Maya 2017.

embed maya native ui objects in pyside2

I’ve had to write a few tools that needed to work in other apps other than Maya so I’ve started to make this function a bit more generic. Hope this helpful to some.

try:
    from PySide import QtGui as QtWidgets
except ImportError:
    from PySide2 import QtWidgets


def getMainWindow():
    """
    Get Main window
    :return: main window 
    """
    mainWindow = QtWidgets.QApplication.activeWindow()
    while True:
        parentWin = mainWindow.parent()
        if parentWin:
            mainWindow = parentWin
        else:
            break
    return mainWindow

I suggest using the Qt.py library which does more checks automatically and industry tested.

1 Like

Does Qt.py include a wrapInstance method? Last time I looked at it, it ignored the sip vs shiboken issues. Had the same problem with qtpy.

Yes it does.

from Qt import QtCompat
QtCompat.wrapInstance()
1 Like

Excellent. That is really great to hear.