Enter button + textField = Maya crashes (Maya 2014)

I’m working on a PyMEL project atm and I just noticed a strange crash (using Maya 2014), and I’m just curious to hear if anyone else has stumbled upon this and what their solution might have been.

I have a textField and a button. The command on the button is the same command as I have on the enterCommand -flag of the textField.
When running the script, pressing the button with the mouse works as it should - but if the user instead press enter on the keyboard, Maya will crash.

I’ve googled around and the only thread I’ve found regarding this bug is this:
http://forums.cgsociety.org/archive/index.php/t-1000345.html

Seems to be a bug with Qt in Maya. Now I’ve never worked with that myself nor installed any extra Qt modules (if there are any).
In the thread above, it is discovered that the cause of the crash is the deletion of the window that the textField resides in. I believe I am experiencing exactly the same thing because my command points to a class method which does some stuff and then finally deletes the window that the textField and the button is parented to. My error log is close to identical to his error log as well.

One person suggests wrapping the entire deletion -code inside an evalDeferred -command, but says it’s not ideal.
I took a look at the PyMEL manual and I can’t say I really see the issue with that solution: pymel.core.general.evalDeferred — PyMEL v1.0.3 documentation

So my question then is this:
Why is it so bad (ie: not ideal) to use evalDeferred() here?

You might just be getting multiple callbacks. Try adding some code that does an early exit so that you don’t crash. If you’re using a class to receive your callbacks, add a class level variable self.callbacks_disabled (or whatever), and if you’re not using a class create a global variable. Then wrap your code in:

if callbacks_disabled:
    return
callbacks_disabled = true

...
do stuff
...

callbacks_disabled = false
return

[QUOTE=btribble;23977]You might just be getting multiple callbacks. Try adding some code that does an early exit so that you don’t crash. If you’re using a class to receive your callbacks, add a class level variable self.callbacks_disabled (or whatever), and if you’re not using a class create a global variable. Then wrap your code in:

if callbacks_disabled:
    return
callbacks_disabled = true

...
do stuff
...

callbacks_disabled = false
return

[/QUOTE]

I don’t follow - what’s an early exit?
My code here is simple, and I don’t think I’m getting multiple callbacks.

There’s two methods in my class that’s active in this operation.
One method for the form (UI - a window), containing just a window with a textfield and two buttons - and one method for the functionality (actual command).

    def someMethod(self, incVar):

        # Main window
        window = pm.window(
            self.someWindow,
            maximizeButton=False, 
            sizeable=False,
            title="Title", 
            width=250
        )
        
        # Create column layout
        self.someCol = pm.columnLayout(rowSpacing=10)
        
        # Create label and input field
        self.someLabel = pm.text(
            align="center", 
            label="the something something", 
            width=240
            )
            
        self.someField = pm.textField(
            alwaysInvokeEnterCommandOnReturn=True,
            annotation="Something",
            enterCommand=lambda *args: self.theCmd(incVar),
            width=240
        )
        
        # Create row layout
        self.someRow = pm.rowLayout(numberOfColumns=2)
        
        # Create buttons
        self.okBtn = pm.button(
            command=pm.Callback( self.theCmd, incVar ),
            label="Ok", 
            width=118
        )
        self.cancelBtn = pm.button(
            command=pm.Callback( pm.deleteUI, self.someWindow ),
            label="Cancel",
            width=118
        )
        
        pm.showWindow( window ) # Display the window


    def theCmd(self, incVar):
        
        # Read data from the textField
        fieldVar = pm.textField( self.someField, query=True, text=True )

        # Some variable operations.
        
        # Some callback objects are created and sent to another function        
        cmd = pm.Callback( self.method1, fieldVar, mode=0, someArg=0 )
        self.updateMethod( self.method2, cmd, fieldVar, self.mySize )
        
        # ...however, all they do is insert those callback objects on the command-flags
        # of the objects they update via self.updateMethod. The callbacks never execute.
        
        # And at the very bottom of the code:
        
        # Close the window
        pm.deleteUI(self.someWindow)

Clicking the Ok-button with the mouse works. But pressing Enter (or keypad enter) in the textField crashes Maya…
And the lambda function there was a test. Prior to that I had pm.Callback(method, var) - same results

Why are you using pm.Callback at all?

I have no issue doing what you described.

Post a full code sample that reproduces the issue. My guess from looking at your code is that the issue is when you call deleteUI in theCmd. If you put the deleteUI in evalDeferred, does it still crash?

Sometimes you have to evalDeferred UI deletion (unless there’s a method around it I don’t know). If you have a popupMenu that deletes a UI element, and the popupMenu is a child of the UI element being deleted, it will crash unless you delete deferred.

Ooh! What Capper said! You can’t delete a UI that is the parent of a running process in PyQt.

Alright, thanks for your replies. I’ll go with evalDeferred.
I’m still curious to hear about what downsides/potential problems there are to using that command though.

evalDeferred? There shouldn’t be any downsides that I’m aware of.

Strangely enough, evalDeferred did not solve this problem.

pm.evalDeferred( pm.deleteUI(self.theWindow), lowestPriority=True )

…still results in a crash. Commenting that row away and Maya no longer crashes - so the crash is definetly related to the window deletion :confused:

evalDeferred takes a callback or string. You are passing it the result of the function call pm.deleteUI(self.theWindow). Use something like:

pm.evalDeferred(lambda: pm.deleteUI(self.theWindow))

[QUOTE=capper;24029]evalDeferred takes a callback or string. You are passing it the result of the function call pm.deleteUI(self.theWindow). Use something like:

pm.evalDeferred(lambda: pm.deleteUI(self.theWindow))

[/QUOTE]

Ah, that explains it; Thanks a bunch!
Case closed!