PySide in Maya 2014 winEvent error

Hey Everybody,

I’ve been implementing a bunch of tools using PySide in 2014 and the fact that it’s distributed with Maya by default is great, especially when dealing with multiple 32/64 bit and on multiple OS’s. So anyway, long story short I’ve been running into this error where if I launch the UI a couple times, after a certain random number of launches, it will complain that QMainWindow (actually my subclass of it) doesnt have an attribute winEvent(). It seems to get called in .show(). I also used .setVisible() instead and still got the error. I read somewhere that nativeEvent() is now the correct call and winEvent() is not longer valid but it seems to be something Maya is doing internally, so I have no way of getting to this. I’m using Nathan Horne’s method of loading the .UI file with sip, but I also generated a .py class from the .UI to see if it would help and it didn’t seem to.

Anyone else had this problem or know of a workaround? Essentially once this happens you just have to restart Maya which is super annoying :slight_smile:

Thanks in advance!
Judd

Actually, after quite a bit of testing I just realized that it only happens if I have reload(myModule) in my launch script.

So for example if I have:

import myTool
reload(myTool)
myTool.showUI()

I’ll have the problem, but if I kill the reload part, then its fine. Any ideas why that is?

Thanks!

Hey Judd,

Not sure if you found a solution to this, but I found a workaround that might work for you.

In my experience, the error arises when a new instance of the window/dialog is repeatedly created, without first deleting the old UI. In my case, I get the error when I excute the PySide script directly in Maya, as opposed to using reload on a module.

By default, close only hides the window, it doesn’t delete it. The trick is to delete the UI (if it exists) before reloading your script. The first thing I do is set the window to delete on close. Then, I make sure to call close on the object (even if it doesn’t exist) before creating the new UI.

class TestUi(QtGui.QDialog):
    
    def __init__(self, parent=maya_main_window()):
        super(TestUi, self).__init__(parent)
        
        self.setWindowTitle("TestUi")
        self.setWindowFlags(QtCore.Qt.Tool)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
              
if __name__ == "__main__":
    
    try:
        ui.close()
    except:
        pass
    
    ui = TestUi()
    ui.show()

Not pretty, and not something I’d recommend in production code, but it does workaround the error and I don’t have to constantly restart Maya. In your case, could you call myTool.close() prior to calling reload().

-ChrisZ

I was having this problem, too. I tried adding the line self.setAttribute(QtCore.Qt.WA_DeleteOnClose), as suggested. That worked. But then I thought, “What if I don’t always want to delete the window on close? Can the caller decide if it wants to delete the window or not?”

So I came up with a function similar to the one above that deletes the ui before creating a new instance:

def showTestWindow():
    global win
    try:
        win.close()
        win.deleteLater()
    except: pass
    win = TestWindowUI()
    win.show()

The addition of the “deleteLater()” function fixed the “winEvent” problem for me.

After doing alot of investigation I have determined that reloading a python module does cause PySide UIs to freak out and throw winEvent errors.

unique to each UI is a fixed number of times the module can be reloaded before the UI will blow up.

I usually wrap Menu Item commands in a try: reload(myModule) except: import myModule so code changes made outside of maya don’t require a maya restart, but this does seem to be the root of the problem.

Was still getting WinEvent Errors so I came up with a different fix. Just make sure your class name is unique.

class qtTool(QtGui.QDialog):

    def closeExistingWindow(self):
        for qt in QtGui.qApp.topLevelWidgets():
            try:
                if qt.__class__.__name__ == self.__class__.__name__:
                    qt.close()
            except:
                pass

    def __init__(self, parent=mayaWindow):

        self.closeExistingWindow()

A year and a half later, I realized that the caller can decide whether to to set the WA_DeleteOnClose. It doesn’t have to be in the class’s code. (Python 101. Very embarrassing on my part. :sigh:)

def showTestWindow():
    global win
    try:
        win.close()
    except: pass
    win = TestWindowUI()
    win.setAttribute(QtCore.Qt.WA_DeleteOnClose)
    win.show()

The difference between this one and the “deleteLater” one is when the window is removed from memory. With the “WA_DeleteOnClose version”, the window is removed from memory when it is closed. With the “deleteLater” version, the window hangs around in memory until “showTestWindow” is run again, even if the user closed the window. (Which could be useful if there are any values you want to retrieve from the closed window. Otherwise it could be wasteful.)

Hi Guys,
im working on a maya gui in pyside done with Qt and i stumbled upon a few questions …

i created my pyside ui class which goes something like this


from PySide import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(640, 486)
        MainWindow.setAcceptDrops(False)
.
.
.

Now inheriting the ui class and launching it like this…


class Window(QMainWindow, danimtoolsUI.Ui_MainWindow):
    def __init__(self, parent = None):

        QMainWindow.__init__(self, parent)

        self.setupUi(self)

a = Window()
a.show()
         

I would like to understand better if im am doing this right… Since i previously had a similar problem as mentioned here , with other ui, where after launching it few times it gave an error message, this time thou, it seems not to(it works!), hence why i am a little suspicious …
previously i was using the
try:
win.close()
except: pass

but since now it works(even opening it lots of times) i would like to better understand if i should use it or not?..

So far i intend to have 3 files, 1 is my ui.py file with the Ui_MainWindow class, and the other would be my Window() class which inherits the ui and the dostuff() class and puts them together, so im wondering if all of this make any sense? I would like to keep things separated so i can update/add/change things easier(or so im thinking…)

Im still pretty new to all this, apologies if my terminology is unexistent …

EDIT:
I found the culprit…windows seems to put your window just underneath your current one, hence why calling the maya window will solve this issue, on Linux instead just works ,the ui window doesn’t seem to have any problem staying where you leave it and unless you want to dock it inside maya i think the call might not be needed…

-a