Search code examples
pythonuser-interfacewindowmaya

Python - How do I go about deleting a custom maya UI window when the user clicks outside of it?


I have a custom window that basically acts as a popup whenever a user clicks on a shelf item.

def drawUI(): 
    mouse_pos = QtGui.QCursor().pos()
    print 'mouse x: %d y: %d' % (mouse_pos.x(), mouse_pos.y())
    if cmds.window("SET_SELECTION_UI", exists = True):
        cmds.deleteUI("SET_SELECTION_UI", window=True)

    cmds.window("SET_SELECTION_UI", title = "Example", wh = (102, 300), rtf=True, mnb = False, mxb = False, tb = False, sizeable = False, tlc=(mouse_pos.y(),mouse_pos.x()))
    cmds.columnLayout()
    cmds.button(label = "Set 00",   w = 100, command=button00)
    cmds.button(label = "Set 10",   w = 100, command=Button10)
    cmds.button(label = "Set 25",   w = 100, command=Button25)
    cmds.separator( height=10, style='double' )
    cmds.button(bgc=[1,1,1], label = "Cancel", w = 100, command=DeleteButton)
    cmds.showWindow() #shows window

    cmds.window("SET_SELECTION_UI", edit=True, tlc=(mouse_pos.y(),mouse_pos.x()))

The window appears properly, all the buttons do what they're supposed to do, and whenever a button is pressed, I delete the window. It's all fine and dandy.

What I'm trying to do, is to detect when the user clicks anywhere outside of the window so that I can delete the UI (much like a pop-up menu works).

Thanks!

ANSWER

I've integrated Cronicryo's script and suggestions into my own and it works perfectly now! Here it is:

from PySide import QtGui, QtCore
import maya.OpenMayaUI as omui
import pymel.core as pm
from shiboken import wrapInstance

fltr    = None
qtObj   = None
_WINDOW_NAME_ = "SET_SELECTION_UI"

class FilterObj(QtCore.QObject):
    def eventFilter(self, obj , event):
        print event.type()
        if event.type() == event.WindowDeactivate:
            print "focused out"
            pm.window(_WINDOW_NAME_,edit=True,visible=False)
            return True #must return a bool set False to allow normal events to pass through or True to stop any further events
        else:
            return False

def run(): 
    global fltr
    global qtObj

    if qtObj:
        del qtObj

    mouse_pos = QtGui.QCursor().pos()
    print 'mouse x: %d y: %d' % (mouse_pos.x(), mouse_pos.y())
    if pm.window(_WINDOW_NAME_, exists = True):
        pm.deleteUI(_WINDOW_NAME_, window=True)

    win = pm.window(_WINDOW_NAME_, title = "Set Select", mnb = False, mxb = False, tb = False, sizeable = False)
    pm.columnLayout()
    pm.button(label = "Do nothing",   w = 100)
    pm.separator( h=15, w=100, style='doubleDash' )
    pm.button(bgc=[1,1,1], label = "Cancel", w = 100, command=DeleteButton)
    pm.showWindow(win) #shows window

    pm.window(_WINDOW_NAME_, edit=True, wh = (102, 245),tlc=(mouse_pos.y(),mouse_pos.x()))

    qtObj = wrapInstance(long(omui.MQtUtil.findControl(_WINDOW_NAME_)), QtGui.QWidget)
    fltr = FilterObj()
    qtObj.installEventFilter(fltr)

def DeleteButton(*args):
    pm.deleteUI(_WINDOW_NAME_)

Solution

  • EDIT:

    i took a look and it looks like there is no focus signal that gets emitted. seems like the only way to do it is to make a custom qt window and re-implement the focus functions or to install an event filter which is almost non evasive

    import maya.OpenMayaUI as omui
    import pymel.core as pm
    pysideSupport = True
    try:
        from PySide import QtGui
        from shiboken import wrapInstance
    except:
        pysideSupport = False
    
    win = pm.window("aaa")
    win.show()
    
    from PySide import QtCore
    
    class FilterObj(QtCore.QObject):
        def eventFilter(self, obj , event):
            print event.type()
            if event.type() == event.WindowDeactivate:
                print "focused out"
                return False #must return a bool set False to allow normal events to pass through or True to stop any further events
            else:
                return False
    
    
    qtObj = wrapInstance(long(omui.MQtUtil.findControl("aaa")), QtGui.QWidget)
    fltr = FilterObj()
    qtObj.installEventFilter(fltr)
    

    ORIG:

    this is a snippet of my own code that ive used to connect to the destroy signal of a window. you can do the same of losing window focus

    import maya.OpenMayaUI as omui
    pysideSupport = True
    try:
        from PySide import QtGui
        from shiboken import wrapInstance
    except:
        pysideSupport = False
    
    
    def onUIDelete(uiName, function):
        """
        extends mayas ui by being able to run a function when the ui gets deleted
        this requires maya to have PySide
    
        """
        if pysideSupport:
            if isinstance(uiName, pm.ui.PyUI):
                uiName = uiName.name()
            qtObj = wrapInstance(long(omui.MQtUtil.findControl(uiName)), QtGui.QWidget)
            qtObj.destroyed.connect(function)
        else:
            pm.error("Maya doesn't have PySide Support")