Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should there be a wrapper around sip/shiboken? #53

Closed
fredrikaverpil opened this issue Jun 3, 2016 · 56 comments
Closed

Should there be a wrapper around sip/shiboken? #53

fredrikaverpil opened this issue Jun 3, 2016 · 56 comments
Labels

Comments

@fredrikaverpil
Copy link
Collaborator

Originally asked by Pierre Augeard:

What would be the wrapper around sip/shiboken?

For example:

@fredrikaverpil fredrikaverpil changed the title Should there be a wrapper around shiboken? Should there be a wrapper around sip/shiboken? Jun 3, 2016
@mottosso
Copy link
Owner

mottosso commented Jun 3, 2016

Originally asked by Pierre Augeard:

Where? :O

@fredrikaverpil
Copy link
Collaborator Author

fredrikaverpil commented Jun 3, 2016

Where?

Over at the Maya beta forums, but now I see he's interacting here. Ping @pipoun

@fredrikaverpil
Copy link
Collaborator Author

@pipoun - could you please provide a use case for this request/question?

@pipoun
Copy link

pipoun commented Jun 7, 2016

from Qt import QtGui, binder
import maya.OpenMayaUI


def get_maya_mainwindow():
    """Get the main Maya window

    :return: :class:`QtGui.QMainWindow` instance of the top level Maya window
    """
    ptr = maya.OpenMayaUI.MQtUtil.mainWindow()
    if ptr is not None:
        # wrap_instance (pep8), wrapInstance (shiboken) or wrapinstance (sip)
        return binder.wrap_instance(long(ptr), QtGui.QMainWindow)

@fredrikaverpil
Copy link
Collaborator Author

fredrikaverpil commented Jun 7, 2016

@pipoun do you ever use this for anything except returning the main Maya window when you want to parent your UI to Maya?

Would you consider this approach or do you feel QtWidgets.QApplication.activeWindow() is too unreliable?

@mottosso
Copy link
Owner

mottosso commented Jun 8, 2016

A portable approach would be preferable. However..

Would you consider this approach

This returns the script editor for me.

from Qt import QtWidgets
window = QtWidgets.QApplication.activeWindow().objectName()
print(window)

Unless I have another window active, in which case that window is returned.

There is this.

from Qt import QtWidgets
window = {w.objectName(): w for w in QtWidgets.qApp.topLevelWidgets()}["MayaWindow"]
print(window)

@pipoun
Copy link

pipoun commented Jun 8, 2016

I just wanted to focus on the fact that sip.wrapinstance and shiboken.wrapInstance have not the same spelling nor the exact same behavior and it should be considered to have a wrapper to unify all of this ?

@pipoun do you ever use this for anything except returning the main Maya window when you want to parent your UI to Maya?

There are other use cases than getting a main window as a QMainWindow instance.

QtWidgets.qApp.topLevelWidgets() is very slow in some cases compared to MQtUtil.mainWindow (when there are many Qt widgets init'd), see the implementation :
http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/kernel/qapplication.cpp#n1776

@mottosso
Copy link
Owner

mottosso commented Jun 8, 2016

Thanks for the added info @pipoun.

Would it be possible to show us some more examples? I haven't used this particular feature myself, so it's difficult to know what and how to wrap.

@mottosso mottosso added feature and removed question labels Jun 9, 2016
@fredrikaverpil
Copy link
Collaborator Author

fredrikaverpil commented Jun 9, 2016

To me, it sounds like there's a need for a convenience function "Qt.wrap_instance()", like this one, by Nathan Horne, previously mentioned:

def wrapinstance(ptr, base=None):
    """
    Utility to convert a pointer to a Qt class instance (PySide/PyQt compatible)

    :param ptr: Pointer to QObject in memory
    :type ptr: long or Swig instance
    :param base: (Optional) Base class to wrap with (Defaults to QObject, which should handle anything)
    :type base: QtGui.QWidget
    :return: QWidget or subclass instance
    :rtype: QtGui.QWidget
    """
    if ptr is None:
        return None
    ptr = long(ptr) #Ensure type
    if globals().has_key('shiboken'):
        if base is None:
            qObj = shiboken.wrapInstance(long(ptr), QtCore.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 = QtGui.QWidget
        return shiboken.wrapInstance(long(ptr), base)
    elif globals().has_key('sip'):
        base = QtCore.QObject
        return sip.wrapinstance(long(ptr), base)
    else:
        return None

I've personally only used this to successfully fetch the Maya main window:

def maya_main_window():
    '"""Returns the main Maya window"""
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapinstance(long(main_window_ptr), QtGui.QWidget)

But for this particular thing, your code is much much nicer, @mottosso. I second @mottosso's request to see additional use cases.

@mottosso
Copy link
Owner

mottosso commented Jun 9, 2016

Yeah, a feature, encompassing 14% of the entire codebase (32/230 LOC), for a single usecase isn't worth it.

Once we find more usecases, I'd be happy to reconsider this.

@mottosso mottosso closed this as completed Jun 9, 2016
@innerhippy
Copy link

Sometimes it's useful to access sip.delete() / shiboken.delete(), especially when redefining layouts, selection models, or running complex unit tests. Admittedly it's only really needed for PyQt4 but it would be useful to abstract this as something like C_binding.

@mottosso
Copy link
Owner

mottosso commented Oct 1, 2016

Hi @innerhippy,

Would it be possible to share an example of where sip could be useful? That would really help determine how to best see it realised.

@fredrikaverpil
Copy link
Collaborator Author

Admittedly it's only really needed for PyQt4

Just a suggestion, would this work for you then?

if "PyQt4" in QtCompat.__binding__:
    sip.delete()
    shiboken.delete()

@mottosso
Copy link
Owner

mottosso commented Oct 1, 2016

What I'm interested in, is whether there is an alternative to using sip.delete() and friends in the first place, that is cross-compatible. But to do that, we'll need examples of where sip is used.

@innerhippy
Copy link

Thanks @fredrikaverpil , that would certainly work and similar to what I was thinking. I guess the consideration is if this should be provided by the Qt module itself. We use it to delete layouts and for some unit tests where the destruction order of models gets a bit messed up (in PyQt4 anyway). I agree that ideally this shouldn't be necessary, and maybe refactoring the code would solve the problem, but sometimes it's a question of having to just making stuff work. I'll post some code snippets on Monday but have to get clearance first.

@boglin
Copy link

boglin commented Oct 19, 2016

Just wanted to add another voice here.

I found this request when looking at porting our stack over to Maya2017 and doing the Qt4->Qt5 shuffle. We have upwards of 20 projects which use wrapinstance - our previous (inhouse) PyQt4/PySide shim provided access to the underlying binding where we used a couple of very specific methods, e.g. wrapInstance, delete, signature/methodsignature where behaviour was comparable.

Common with others on this thread the largest use is wrapInstance generally against the Maya API:
MQtUtil Class Reference, where *QObject/QWidget is returned.

We could ask people to port to pymel: uitypes.py within Maya-specific code, which is already providing this switching logic. But the API brings us back to a specific PyQt/PySide implementations which is what makes Qt.py so attractive.

I guess the reason why we see so much of this in the codebase is that Maya's examples are driving people towards wrapInstance: Autodesk Docs: Working with PySide in Maya I would love for us to be able to produce a translation of that document as "Working with Qt.py in Maya".

If people are happy for it to be added - I'd be happy to help put together a patch.

@mottosso
Copy link
Owner

I would love for us to be able to produce a translation of that document as "Working with Qt.py in Maya".

Good idea. Perhaps as an extension of Fredrik's document.

To include pros and cons of these binding-specific methods. Could also be elsewhere, even in the README of this project since it maybe relevant enough.

@innerhippy
Copy link

To follow up on my post from 1st Oct, here's an example of where we use the delete function:

def deleteLayout(widget, layout=None, deleteTopLevelLayout=True):
   """ Function to delete a widget's layout. This needs to be done in
        reverse order of each item in the layout as the index is changed
        for each itemAt() call.
        If deleteTopLevelLayout==True, the layout is deleted using the sip 
        module to ensure that all underlying C++ destructors are called,
        otherwise the layout will have stale widgets from the previous
        setLayout() calls
    """"
    if widget is not None and layout is None:
        layout = widget.layout()

    if layout is not None:
        for i in xrange(layout.count()-1, -1, -1):
            item = layout.itemAt(i)

            if isinstance(item, QtGui.QWidgetItem):
                item.widget().setParent(None)
            elif isinstance (item, QtGui.QLayoutItem):
                # recursive call if the item is a layout
                deleteLayout(item)
        if deleteTopLevelLayout:
            import sip
            sip.delete(layout)

@mottosso
Copy link
Owner

That is perfect @innerhippy! Thanks for that!

@fredrikaverpil
Copy link
Collaborator Author

fredrikaverpil commented Oct 19, 2016

I guess the reason why we see so much of this in the codebase is that Maya's examples are driving people towards wrapInstance: Autodesk Docs: Working with PySide in Maya I would love for us to be able to produce a translation of that document as "Working with Qt.py in Maya".

If people are happy for it to be added - I'd be happy to help put together a patch.

In case you decide to start doing this, you can fork this project and make a pull request with the translation. If anyone has the time he/she can join in and help out by making pull requests to your fork. This way it could become a collaborative process.

Good idea. Perhaps as an extension of Fredrik's document.

To include pros and cons of these binding-specific methods. Could also be elsewhere, even in the README of this project since it maybe relevant enough.

If this were to be created, I think it would be useful to keep it as a markdown file (linked from the README) here in the repository.

@glm-nchaverou
Copy link

glm-nchaverou commented Jan 25, 2017

Hi guys,
Sorry to jump in the discussion.
First thanks for Qt.py, it's been a huge lifesaver here at Golaem !!
I've ported all our code to it but there's still a function which relies around wrap_instance that I can't convert (yet). We're having a findLayout function which relies on Nathan Ortiz one (http://nathanhorne.com/embedding-a-maya-widget-into-a-pyqt-ui/). This allows us fetching the Attribute Editor layout of a specific node and override it with our own QT controllers (such as this one:

image

For sure a wrapInstance binding will be awesome but I let this decision up to you :)
Let me know if you need more info

@mottosso
Copy link
Owner

Hi @glm-nchaverou! Thanks for the kind words, and you are most welcome to join the discussion.

I can see the use of wrapping sip/shiboken, but I'm still out the lookout for reason enough to warrant it. So far, the uses I have seen and been shown have had a non-sip equivalent; the most prominent being parenting to the main Maya window.

Let me know if you need more info

If you could provide me with an example of doing what you're looking to do, in this case modifying the Attribute Editor, using sip/shiboken, then I'd be happy to try and find a non-sip/shiboken equivalent.

If there is none, then that would be the best of reasons to start looking at wrapping enough of it to facilitate what you are looking to do.

@mottosso
Copy link
Owner

I couldn't find how to get the Attribute Editor, but if it's similar to finding the Channel Box, then maybe this could be of help.

Shiboken

import shiboken
import maya.OpenMayaUI as apiUI
from Qt import QtWidgets
channel_box = apiUI.MQtUtil.findControl("mainChannelBox")
channel_box = shiboken.wrapInstance(long(channel_box), QtWidgets.QTableView)
channel_box.setStyleSheet("QWidget {background: red}")

Pure Qt

from Qt import QtWidgets
app = QtWidgets.QApplication.instance()
window = {o.objectName(): o for o in app.topLevelWidgets()}["MayaWindow"]
channel_box = window.findChild(QtWidgets.QTableView, "mainChannelBox")
channel_box.setStyleSheet("QWidget {background: green}")

@glm-nchaverou
Copy link

Hey,

Ok here's how we hacked the AttributeEditor (can't find who we inspired this first... sorry)

In the AEMyNodeTemplate.mel file:

global proc AEMyNodeTemplate( string $nodeName )
{
    ...
    editorTemplate -callCustom "melbuildQT" "melUpdateQT" "";
    ...
}

melBuildQT( string $nodeName )
{
    string $parent = `setParent -q`;
    python("buildQT('" + $parent + "')");
}

And on the Python side:

def buildQT(layout):
    mayaLayoutPtr = omui.MQtUtil.findLayout(layout)
    mayaLayout = wrapInstance(long(mayaLayoutPtr), QtWidgets.QWidget)
    mayaLayoutObj = mayaLayout.findChild(QtWidgets.QBoxLayout)
    #add the widget to the layout
    mayaLayoutObj.insertWidget(0,widget)

It should highlight eveything :)
Let me know if not

@mottosso
Copy link
Owner

mottosso commented Feb 8, 2017

Hi @glm-nchaverou,

I'm having trouble running your example with the Attribute Editor Template. Could you post a full template for me, along with how I use it?

@mottosso
Copy link
Owner

mottosso commented Feb 8, 2017

Hi @ben-hearn-sb,

Let me know if this works for you.

from maya import mel
from Qt import QtWidgets

def getMayaStatusLine():
    window = {o.objectName(): o for o in QtGui.qApp.topLevelWidgets()}["MayaWindow"]
    gStatusLine = mel.eval('$temp=$gStatusLineForm')
    statusLine = window.findChild(QtGui.QWidget, gStatusLine)
    return statusLine

statusLine = getMayaStatusLine()
statusLine.setStyleSheet("QWidget {background: red}")

Having tried a few examples at this point, the pattern seems to be that wherever there is a findLayout or findControl you replace it with window.findChild. Any reference to sip or shiboken is included in that call, as passing the superclass you are looking for. Such as QtWidgets.QLayout or QtWidgets.QWidget.

@glm-nchaverou
Copy link

glm-nchaverou commented Feb 15, 2017

Hey @mottosso, sorry for the late answer was stucked with work those past days
Find attached a small 101 maya plugin showing how to hack the AEditor

  • glmDummyNode.py defines a Maya node named DummyNode and all entry point (use the Plugin manager to load it)
  • AEDummyNodeTemplate.mel is the node MEL template for display within the Attribute Editor. It calls some buildQT and updateQT function in a convenient place
  • DummyNodeUI.py contains the buildQT and updateQt functions which shows how to grab the Maya Layout and write custom stuff in it (here it just inserts a QLabel)
    DummyNode.zip

Let me know if you have any question

@mottosso
Copy link
Owner

Thanks @glm-nchaverou, can't quite get it to work. Here's what I did.

  1. Unzip DummyNode.zip into $HOME/maya/scripts/AETemplates
  2. Load glmDummyNode.py through the Maya 2015 plug-in manager
  3. cmds.createNode("DummyNode")
  4. In the Attribute Editor, I'm not seeing any QLabel, and no error messages.

Sorry, I have no experience with AETemplates and Autodesk's help page haven't been very helpful.

What am I doing wrong?

@glm-nchaverou
Copy link

Oops sorry, assumed you're using Maya regularly :)
Maya needs to know where to source scripts from. You can put both AEDummyNodeTemplate.mel and DummyNodeUI.py into a dir referenced within %MAYA_SCRIPT_PATH%
On Win, it's usually C:\Users\chaverou\Documents\maya\2016\scripts :)

@glm-nchaverou
Copy link

Those will be sourced automatically
If the AEXXTemplate is loaded, you should see the following in the AE for this node:
2017-02-15 19_21_52-autodesk maya 2016 - not for resale_ untitled_ --- dummynode1
If the python UI file is loaded correctly, you should see this label on top :
2017-02-15 19_23_02-autodesk maya 2016 - not for resale_ untitled_ --- dummynode1

@mottosso
Copy link
Owner

Oops sorry, assumed you're using Maya regularly :)

Haha, I do. Just not AETemplates.

If the AEXXTemplate is loaded, you should see the following in the AE for this node:

Ok, that did the trick. Thanks.

The Python file had a reference to Qtpy.Qt that I changed into Qt which got the error to stop appearing.

How can I reload the AETemplate? Do I restart Maya each time?

@glm-nchaverou
Copy link

glm-nchaverou commented Feb 15, 2017

Ah yes sorry !! I should have warned about Qt.py :) but, well, looks like you're used to use it :)
DummyNode_updateQT gets called every time you unselect / reselect the node. Just source a function within the same name in the Script Editor to overwrite it :)
The rest is static and will require you to restart Maya I'm afraid

@mottosso
Copy link
Owner

Ok, here we go.

from Qt import QtWidgets, QtCore

# Cache main window so that it is only computed once.
app = QtWidgets.QApplication.instance()
window = {o.objectName(): o for o in app.topLevelWidgets()}["MayaWindow"]


def buildQT(layout, node):
    """Build QT Widget"""

    ae = window.findChild(QtCore.QObject, "MainAttributeEditorLayout")
    form = ae.findChild(QtCore.QObject, "AEcontrolFormLayout")

    # The last element of the AE layout is expected to differ across runs
    # or opening/closing of the AE, so we grab the last entry.
    mayaLayout = form.findChild(QtCore.QObject, layout.rsplit("|", 1)[-1])

    mayaLayoutObj = mayaLayout.findChild(QtWidgets.QBoxLayout)

    widget = QtWidgets.QLabel()
    widget.setText('my uber awesome label')

    mayaLayoutObj.insertWidget(0, widget)


def updateQT(layout, node):
    pass

No other change to the template or plug-in.

The trick here was to look at the value of layout, which was this.

MayaWindow|MainAttributeEditorLayout|formLayout2|AEmenuBarLayout|AErootLayout|AEStackLayout|AErootLayoutPane|AEbaseFormLayout|AEcontrolFormLayout|AttrEdDummyNodeFormLayout|scrollLayout2|columnLayout4|frameLayout29|columnLayout5|columnLayout6

It's the location of the Qt widget in the widget hierarchy. With this information, we spot a few key members, such as MainAttributeEditor and right before getting to DummyNode specifically, a layout called AEcontrolFormLayout.

Assuming these are fixed and consistent across versions of Maya and user sessions, the only remaining thing to do was to grab the layout, which is expected to have a unique name within this narrow space. The rest is noise.

Let me know what you think.

@glm-nchaverou
Copy link

Looks good enough to me.
I'll have to check that it's consistent through all existing versions of Maya and upcoming ones :)
Thanks a ton for the handy tip

@mottosso
Copy link
Owner

mottosso commented Feb 16, 2017

If you wanted to play it safe, you could traverse the hierarchy as given. I'd imagine this is what Maya's findLayout is doing under the hood.

This runs in the Maya Script Editor, though odds are the final element will differ because of the dynamic generation of Maya's Attribute Editor. The concept however is sound.

from Qt import QtWidgets, QtGui, QtCore

hierarchy = "MayaWindow|MainAttributeEditorLayout|formLayout2|AEmenuBarLayout|AErootLayout|AEStackLayout|AErootLayoutPane|AEbaseFormLayout|AEcontrolFormLayout|AttrEdDummyNodeFormLayout|scrollLayout2|columnLayout4|frameLayout29|columnLayout5|columnLayout6"
window = {o.objectName(): o for o in QtWidgets.QApplication.instance().topLevelWidgets()}["MayaWindow"]

# Previous method
ae = window.findChild(QtCore.QObject, "MainAttributeEditorLayout")
form = ae.findChild(QtCore.QObject, "AEcontrolFormLayout")
layout = form.findChild(QtCore.QObject, hierarchy.rsplit("|", 1)[-1])

# Safe method
parent = window
for child in hierarchy.split("|")[1:]:
  parent = parent.findChild(QtCore.QObject, child)

# Prove that the results are identical
assert parent == layout

The final child is guaranteed to exist, as it is given by Maya. As your code runs synchronously, there is no chance of the hierarchy changing whilst it runs.

Having said that, I'm sure there is a better way of achieving your goal if we aren't trying to mimic code written specifically for use with shiboken/sip.

@glm-nchaverou
Copy link

glm-nchaverou commented Mar 16, 2017

Hi,
Jumping back on this again (yeah I know, sorry :))
While the solution proposed worked efficiently for docked main attribute editor, it doesn't for floating Attribute Editors... Maya allows to use the Copy Tab button of an AE to create a dupplicated floating AE window

Thus a Layout which is named..

MayaWindow|MainAttributeEditorLayout|formLayout87|AEmenuBarLayout|AErootLayout|AEStackLayout|AErootLayoutPane|AEbaseFormLayout|AEcontrolFormLayout|AttrEdCrowdChOpSensorInputFormLayout|scrollLayout2|columnLayout5|frameLayout37|columnLayout8|columnLayout9

..in the Main AE is now named..

MayaWindow|nexFloatWindow|paneLayout1|scrollLayout1|formLayout46|formLayout48|frameLayout9|frameLayout10|formLayout49

...in a floating one.

OpenMayaUi findLayout works like a charm in this situation.

Editor note: Formatted long layout names

@mottosso
Copy link
Owner

Jumping back on this again (yeah I know, sorry :))

Not a problem! This isn't over until we've found at least 1 case where a cross-compatible solution is not possible.

If you could post an example of what doesn't work, I'd be happy to take a closer look.

@dgovil
Copy link
Contributor

dgovil commented Mar 28, 2017

Just wanted to add my 2c. I think it would be great if there was an abstraction to wrapInstance as we use it in a few tools especially when we mix Python/C++ Qt, and it's not just limited to Maya.

There are actually quite a few tools that are useful in sip/shiboken unfortunately they don't keep those consistent which is annoying. But wrapInstance/wrapinstance would definitely get the most mileage.

I think @boglin had the best implementation for this: https://github.com/boglin/Qt.py/tree/c_binding
We might merge that into our internal copy of SpiQt because it would definitely be handy.

@mottosso
Copy link
Owner

Thanks @dgovil.

To everyone, please let me know if this is just me.

So far, there are 46 comments in this thread. Half of them is requests for wrapInstance with Qt.py, and the other half is me saying no.

  • The half saying no includes reasoning and examples of alternatives that requires less user code and less library implementation.
  • The half making the request says "it would be useful" and leaves it at that.

Now I would be most delighted to include something I felt was worth including, but that worth can't be built on anything but communication. The request you are making is nonsensical and unnecessary.

So tell me, what would you do?

Against my better judgement and due to the overwhelming number of requests, I've made a PR just now with a cross-compatible solution that I hope will live up to your expectations.

@dgovil
Copy link
Contributor

dgovil commented Mar 29, 2017

I agree with you on that ideally Qt.py should not have to handle it, since like you said there are other ways to achieve the same.

Unfortunately the other methods require some form of traversal of hierarchies or knowing what elements are called (which may change in the future) whereas if there's a guaranteed way to get a pointer from c++ or Python (for example with Maya's getMainWindow function) , the directness would be worth it.

There's also the matter of education. The majority of reference and experience so far online says to use wrapInstance. While alternatives exist like you suggested, people will end up using sip/shiboken directly which kind of negates some of the benefits of qt.py in not having to worry about what binding is being used.

So yes I totally agree with you on that there are better ways to do it, but I think it's just so common that it would be beneficial to have it here. I realize that potentially opens the floodgate of "well what about this feature?" But I think that the rest of sip/shiboken are so incompatible it won't happen.

Your PR looks like it hits the sweet spot of giving the most bang for the buck.

@ben-hearn-sb
Copy link

ben-hearn-sb commented Apr 20, 2017

Hello all,

Sorry for the late replies we have jumped back onto Maya2017 integration here at the studio and I am ready to give my 2cents back to the discussion. I am testing the proposed solutions now. They work for the statusline and the main maya window although @mottosso suggestion does not work for me at the moment. Is it absolutely necessary to replace the Shiboken stuff since I am only using it for the statusline?

I am getting the main Maya window and storing it like so:

def storeMayaWindow():
  ptr = apiUI.MQtUtil.mainWindow()
  if ptr is not None:
    app = QtWidgets.QApplication.instance()
    global_config.mayaMainWindow = {o.objectName(): o for o in app.topLevelWidgets()}["MayaWindow"]

and returning my statusline like so:

def getMayaStatusLine():
  gStatusLine = mel.eval('$temp=$gStatusLineForm')
  ptr = apiUI.MQtUtil.findControl(gStatusLine)
  if ptr is not None:
    statusLine = shiboken2.wrapInstance(long(ptr), QtWidgets.QWidget)
    #statusLine = c_binding.wrapInstance(long(ptr), QtWidgets.QWidget)
    return statusLine.children()[1].children()[1]

@mottosso
Copy link
Owner

Hi @ben-hearn-sb,

@mottosso suggestion does not work for me at the moment.

Could you let me know what exactly isn't working?

@ben-hearn-sb
Copy link

@mottosso yes of course it was this snippet that did not work for me

from maya import mel
from Qt import QtWidgets

def getMayaStatusLine():
    window = {o.objectName(): o for o in QtGui.qApp.topLevelWidgets()}["MayaWindow"]
    gStatusLine = mel.eval('$temp=$gStatusLineForm')
    statusLine = window.findChild(QtGui.QWidget, gStatusLine)
    return statusLine

@mottosso
Copy link
Owner

mottosso commented May 2, 2017

Thanks Ben, here's a modified copy that works.

from maya import mel
from Qt import QtWidgets

def getMayaStatusLine():
    app = QtWidgets.QApplication.instance()
    window = {o.objectName(): o for o in app.topLevelWidgets()}["MayaWindow"]
    gStatusLine = mel.eval('$temp=$gStatusLineForm')
    statusLine = window.findChild(QtWidgets.QWidget, gStatusLine)
    return statusLine

statusLine = getMayaStatusLine()
statusLine.setStyleSheet('QWidget {background: "steelblue"}')

Changes:

  1. QtGui was not imported
  2. QWidget doesn't reside in QtGui
  3. qApp was deprecated

@fredrikaverpil
Copy link
Collaborator Author

fredrikaverpil commented May 10, 2017

I'm not sure if this affects any future feature of Qt.py, such as a wrapper around shiboken, but I figured I'd just mention it:

Hi all,

you know that the PySide(2) project is sub-divided into three main parts (no tools or examples):

pyside-setup, shiboken and pyside.

We have been fighting with this structure quite often. It is sometimes really hard to keep the repositories in sync when we have several open branches in the workings.

I know there are people who are using shiboken separately. They need to change their workflow a little bit, because they now need to checkout pyside and copy shiboken out of it.

If you see a problem with that, please contact us now. We will for sure find a solution together.

Please see more here at the PySide mailing list:
http://lists.qt-project.org/pipermail/pyside/2017-May/002492.html

@OEP
Copy link
Contributor

OEP commented Feb 26, 2018

Hopefully this is the right issue, but I'm hearing from our developers it is occasionally required to use shiboken/shiboken2.isValid() in rare cases where Qt has cleaned up an underlying C++ object from underneath Python. I think we will work around by exposing it in our internal libraries. I'm not asking for it to be exposed by Qt.py, but just noting that here since I didn't see it discussed while researching.

@mottosso
Copy link
Owner

@OEP It's better suited for a separate issue, I think. Since it's a missing member. If you pop one up, or better yet, submit a PR for it, I'm happy to see this included!

@fredrikaverpil
Copy link
Collaborator Author

Just doing some autumn cleaning...

@fredrikaverpil fredrikaverpil closed this as not planned Won't fix, can't repro, duplicate, stale Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants