Maya 2017, Pyside 2, "wrapInstance"

maya
python
qt

#1

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)

#2

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)

#3

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

#4

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

#5

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


#6

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')

#7

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!


#8

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”.


#9

> 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.


#10

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

embed maya native ui objects in pyside2


#11

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

#12

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


#13

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.


#14

Yes it does.

from Qt import QtCompat
QtCompat.wrapInstance()

#15

Excellent. That is really great to hear.