Load up PySide window and lock main Maya window behind it

1,884 views
Skip to first unread message

Fredrik Averpil

unread,
Oct 6, 2014, 5:37:15 AM10/6/14
to python_in...@googlegroups.com

Hi,

You know how the save dialog locks up the Maya UI and only allows you to interact with the save dialog… do you know how can this be achieved when loading up a custom PySide window?

I’m doing this at the moment, which makes sure that the custom ui stays on top of Maya, but it doesn’t lock up the main Maya window in the same way the save dialog does:

from PySide import QtGui

class MyApp(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MyApp, self).__init__(parent)

        self.centralWidget = QtGui.QWidget(self)
        self.setCentralWidget(self.centralWidget)
        self.mainLayout=QtGui.QVBoxLayout(self.centralWidget)
        self.list_widget = QtGui.QListWidget()
        self.mainLayout.addWidget(self.list_widget)

my_app = MyApp( parent=QtGui.QApplication.activeWindow() )
my_app.show()

Cheers,
Fredrik

Marcus Ottosson

unread,
Oct 6, 2014, 5:46:30 AM10/6/14
to python_in...@googlegroups.com

Hi Fredrik,

This behaviour is called “modality”. Have a look here:

Best,
Marcus


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAD%3DwhWMVD1vAj3pyJLBEjmNRm0R5p5%2BuaTDzxD7oOEW%3D0MvfgA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Oct 6, 2014, 5:49:34 AM10/6/14
to python_in...@googlegroups.com

You can either set the modality setting as Marcus mentioned, or you can use exec_() instead of show() which automatically does a modal window and also blocks on the call until it is accepted or rejected.

Mahmoodreza Aarabi

unread,
Oct 6, 2014, 5:55:07 AM10/6/14
to python_in...@googlegroups.com

I use this:

"""This Is A Template Of PySide Programs In Maya"""

from PySide.QtCore import *
from PySide.QtGui import *

from maya import OpenMayaUI
from maya import cmds

import shiboken

class Window(QDialog):
    """docstring for Window"""

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)

        # custom code here
        self.resize(500, 500)

def getMainWindow():
    ptr = OpenMayaUI.MQtUtil.mainWindow()
    mainWin = shiboken.wrapInstance(long(ptr), QMainWindow)
    return mainWin

def show():
    win = Window(parent = getMainWindow())
    win.show()
    win.raise_()

show()


For more options, visit https://groups.google.com/d/optout.



--


Bests,
madoodia

Fredrik Averpil

unread,
Oct 6, 2014, 7:05:29 AM10/6/14
to python_in...@googlegroups.com
Thanks guys,

So I think my main problem was I was inheriting QtGui.QMainWindow and not QtGui.QWidget or QtGui.QDialog. It seems you cannot load a QMainWindow as a modal window.

I really never quite grasped the concept of a modal window before, so thanks for that link Marcus.

Regards,
Fredrik

Marcus Ottosson

unread,
Oct 6, 2014, 7:17:37 AM10/6/14
to python_in...@googlegroups.com
You're welcome, Fredrik. :) Glad you got it sorted.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Fredrik Averpil

unread,
Oct 6, 2014, 7:29:49 AM10/6/14
to python_in...@googlegroups.com

Guys, I was wrong (again). You can set a QMainWindow to modal using setWindowModality(). The code below works for me in Maya:

class MyApp(QtGui.QMainWindow):
    def __init__(self, parent=None):

        super(MyApp, self).__init__(parent)

        self.centralWidget = QtGui.QWidget(self)
        self.setCentralWidget(self.centralWidget)
        self.mainLayout=QtGui.QVBoxLayout(self.centralWidget)
        self.list_widget = QtGui.QListWidget()
        self.mainLayout.addWidget(self.list_widget)

my_app = MyApp( parent=QtGui.QApplication.activeWindow() )
my_app.setWindowModality(QtCore.Qt.WindowModal)
my_app.show()

Marcus Ottosson

unread,
Oct 6, 2014, 7:47:30 AM10/6/14
to python_in...@googlegroups.com

The difference here is that exec_(), as mentioned by Justin, will block until the window closes. Can be useful if you expect results from a window, such as in a save-dialog returning a path. However I think exec_ is only available on QDialog subclasses.

What’s that QtGui.QApplication.activeWindow() you’ve got there? Is that an alternative to getting the shiboken handle, as in Mahmood’s example?

Best,
Marcus


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Fredrik Averpil

unread,
Oct 6, 2014, 8:01:26 AM10/6/14
to python_in...@googlegroups.com

The difference here is that exec_(), as mentioned by Justin, will block until the window closes. Can be useful if you expect results from a window, such as in a save-dialog returning a path. However I think exec_ is only available on QDialog subclasses.

Ah yes. In my particular case, I don’t need that - so I was very happy to find this setWindowModality() solution. I may be wrong here but I also think exec_() available for QtGui.QWidget.

What’s that QtGui.QApplication.activeWindow() you’ve got there? Is that an alternative to getting the shiboken handle, as in Mahmood’s example?

It was something I came by over at stackoverflow… works great for me in both Maya and Nuke (PySide), returns the active Maya window.
http://qt-project.org/doc/qt-4.8/qapplication.html#activeWindow

Marcus Ottosson

unread,
Oct 6, 2014, 8:08:31 AM10/6/14
to python_in...@googlegroups.com

It was something I came by over at stackoverflow… works great for me in both Maya and Nuke (PySide), returns the active Maya window.
http://qt-project.org/doc/qt-4.8/qapplication.html#activeWindow

Then it looks like you just stumbled upon a holy grail. :) Fetching this handle has always been a PITA and this looks simple and logical. Will be trying this out next. Thanks!

I may be wrong here but I also think exec_() available for QtGui.QWidget.

You can see everything it supports here:
http://qt-project.org/doc/qt-4.8/qwidget-members.html

Best,
Marcus


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Fredrik Averpil

unread,
Oct 6, 2014, 8:35:44 AM10/6/14
to python_in...@googlegroups.com

Then it looks like you just stumbled upon a holy grail. :) Fetching this handle has always been a PITA and this looks simple and logical. Will be trying this out next. Thanks!

Nice, let me know how it works. I have only used this with QMainWindow and QDialog. I don't think it will work with QWidget.

 

I may be wrong here but I also think exec_() available for QtGui.QWidget.

You can see everything it supports here:
http://qt-project.org/doc/qt-4.8/qwidget-members.htm

Ah... so QWidget did not have exec_().

Marcus Ottosson

unread,
Oct 6, 2014, 11:46:52 AM10/6/14
to python_in...@googlegroups.com

That’s brilliant, Fredrik.

I did some tests and it looks like it’s returning the currently active window (duh!), which in the case of running from the Script Editor is the Script Editor window. Not sure it has any repercussions and shouldn’t be an issue when not running from the Script Editor.

However, I also tried this.

from PySide import QtGui

# Returns the Script Editor, sometimes.
window = QtGui.QApplication.activeWindow()
assert window.objectName() == 'scriptEditorPanel1Window'

# Returns the Maya Window, for sure
widgets = dict((w.objectName(), w) for w in QtGui.QApplication.allWidgets())
window = widgets['MayaWindow']

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Oct 6, 2014, 3:00:50 PM10/6/14
to python_in...@googlegroups.com
I'm not sure I would consider activeWindow() the "holy grail" since it has circumstances where it will not return the Maya main window, depending on how your tool was launched. If it happens to be launched when the main window does not have focus, or if any other tools are running in top level windows with focus, it could return None or another window. Even if going through the shiboken/sip layer is a pain, you can at least be sure you will instantly find the main window properly even if they rename the object name to "foo" in the next release.

But if you do want to loop over the existing widgets looking for the "MayaWindow" object name, you could reduce the number of widgets a great deal if you use QApplication.topLevelWidgets() instead of allWidgets() 



Marcus Ottosson

unread,
Oct 6, 2014, 3:35:06 PM10/6/14
to python_in...@googlegroups.com

QApplication.topLevelWidgets()

Perfect, looks great to me. Why go through a PySide/PyQt-dependent extra layer of shiboken/sip wrapping when you could do this? And don’t tell me it’s for performance, as this is a one-off. ;)

After all, looping through allWidgets() takes ~0.018 seconds.

start = time.time()
dict((w.objectName(), w) for w in QtGui.QApplication.allWidgets())
print time.time() - start

Whereas topLevelWidgets() takes ~0.002 seconds.

start = time.time()
dict((w.objectName(), w) for w in QtGui.QApplication.topLevelWidgets())
print time.time() - start


For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Oct 6, 2014, 3:42:13 PM10/6/14
to python_in...@googlegroups.com
I wouldn't say its a performance thing. It's more just about whether you want to discover the Maya main window yourself, or be told by the API exactly where it is. If the objectName will never change, then you will end up with the same result. If they say in the docs "'MayaWindow' will always be the name of the main window", then at least you have that guarantee. But I don't think they do that anywhere. 

Marcus Ottosson

unread,
Oct 7, 2014, 4:56:18 AM10/7/14
to python_in...@googlegroups.com

That’s a good point. I suppose the API is less likely to change, than the objectName of the Maya window, which might even have that name set by coincidence as many of Maya’s other widgets don’t have any namy, as can be seen by the allWidgets() command.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Fredrik Averpil

unread,
Oct 8, 2014, 4:08:38 AM10/8/14
to python_in...@googlegroups.com

I second that you should ask the API if you are not 100% certain from where you are launching the UI. I know for a fact that this application I’m developing can only be launched from the Maya/Nuke file menus (or the Maya shelf) by the user. So in this case, it works fine to set the parent of my UI to QtGui.QApplication.activeWindow().


Marcus Ottosson

unread,
Oct 8, 2014, 4:26:09 AM10/8/14
to python_in...@googlegroups.com

I know for a fact that this application I’m developing can only be launched from the Maya/Nuke file menus (or the Maya shelf) by the user.

Until someone would like to extend your tool and try to script it. :) I’d be careful, this is how tight-coupling is born.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Oct 8, 2014, 4:51:37 AM10/8/14
to python_in...@googlegroups.com
I agree. Just because you happen to launch it from a menu now, doesn't mean someone won't try and use it via another approach. It may not always be best to design the tool to expect that it will be launched through a specific mechanism. 

Fredrik Averpil

unread,
Oct 8, 2014, 4:53:12 AM10/8/14
to python_in...@googlegroups.com
Hm. That makes sense. I might revise that code, but any modal dialogs that open up from it, I probably won't change.

Justin Israel

unread,
Oct 8, 2014, 4:57:18 AM10/8/14
to python_in...@googlegroups.com
Totally reasonable. What the application does at that point makes sense. At least it wont make assumptions about how it is launched. You could always supply the parent (activeWindow()) via the menu-specific code as opposed to the core application code. That would mean your menu launches it one way, while some other approach would instance and supply a parent another (or just use the default). 

On Wed, Oct 8, 2014 at 9:52 PM, Fredrik Averpil <fredrik...@gmail.com> wrote:
Hm. That makes sense. I might revise that code, but any modal dialogs that open up from it, I probably won't change.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Fredrik Averpil

unread,
Oct 8, 2014, 5:39:40 AM10/8/14
to python_in...@googlegroups.com
Yes, totally agreed on such a practice.

Marcus Ottosson

unread,
Oct 8, 2014, 5:52:41 AM10/8/14
to python_in...@googlegroups.com
Totally!

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Reply all
Reply to author
Forward
0 new messages