PyQt Plugin blocks Maya update

I developed a plugin with the Python internal GUI and now wanted to change to PyQt. I now found that, whenever I load and start the plugin, maya does not update its scene screen anymore.

E.g.: I have a simple box in the scene. Once my plugin is loaded and I select the box, I do not see the selection of the box until I move around in the scene (e.g. rotate the camera). Since my plugin changes the scene and even can start an animation, this is really annoying. I post party of my code to give you a better idea.

Thanks for your help guys

###########################################################

import maya.OpenMaya as OpenMaya
import maya.OpenMayaAnim as OpenMayaAnim
import sys
import math
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds

import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui
import sip

kPluginCmdName = "MakeMeSwim";

##### Deformer class does all the calculations and set keyframes #####
class Deformer:
    [...]

class MainWindow(QtGui.QMainWindow):

    applyAnimSignal = QtCore.pyqtSignal(int, float, float, int, int, int,name='applyAnimSignal')

    def __init__(self, *args):
        QtGui.QMainWindow.__init__(self, *args)
        self.setWindowTitle('Make Me Swim')
        self.vertical = QtGui.QVBoxLayout()

        self.horizontal1 = QtGui.QHBoxLayout()
        self.axis1 = QtGui.QRadioButton("x-axis");
        self.axis1.setChecked(1);
        self.axis2 = QtGui.QRadioButton("y-axis");
        self.axis3 = QtGui.QRadioButton("z-axis");

        [...]

#### register command and connect to UI #####
class scriptedCommand(OpenMayaMPx.MPxCommand):
 def __init__(self):
  OpenMayaMPx.MPxCommand.__init__(self);
 def doIt(self,argList):
    app = QtGui.QApplication(sys.argv)
    mainWindow = MainWindow()
    deform=Deformer();
    app.connect(app, QtCore.SIGNAL("lastWindowClosed()"),app, QtCore.SLOT("quit()"))
    mainWindow.applyAnimSignal.connect(deform.addAnimation)
    mainWindow.show()
    app.exec_()

# Creator
def cmdCreator():
 return OpenMayaMPx.asMPxPtr( scriptedCommand() );

# Initialize the script plug-in
def initializePlugin(mobject):
 mplugin = OpenMayaMPx.MFnPlugin(mobject);
 try:
  mplugin.registerCommand( kPluginCmdName, cmdCreator );
 except:
  sys.stderr.write( "Failed to register command: %s\n" %kPluginCmdName );
  raise;

# Uninitialize the script plug-in
def uninitializePlugin(mobject):
 mplugin = OpenMayaMPx.MFnPlugin(mobject);
 try:
  mplugin.deregisterCommand( kPluginCmdName );
 except:
  sys.stderr.write( "Failed to unregister command: %s\n" %kPluginCmdName );
  raise;

###############################################################

Hi,

You are not hooking the Maya QT applicationj instance, but rather creating your own.

Do not do that.

You need something along these lines:

import maya.OpenMayaUI as apiUI
import sip
def GetMayaMainWindow(): 
      """ @return: `QtWidget` that pertains to the Maya Main Window """
      try: 
            ptr = apiUI.MQtUtil.mainWindow() 
            return sip.wrapinstance(long(ptr), QtCore.QObject) 
      except: 
           return None

 

HTH

Cheers. 

Hi,

thanks for your quick help. But what do I do with this maya main window then? I changed my QMainWindow to be a QWidget. I tried to hand in the maya main window as a parent of the widget. That seemed to not work. Maybe I should also mention that I use Maya 2008.

Whatelse do I need to change in the following lines?

 def doIt(self,argList):
    app = QtGui.QApplication(sys.argv)
    mainWindow = MainWindow(GetMayaMainWindow())
    deform=Deformer();
    app.connect(app, QtCore.SIGNAL("lastWindowClosed()"),app, QtCore.SLOT("quit()"))
    mainWindow.applyAnimSignal.connect(deform.addAnimation)
    mainWindow.show()
    app.exec_()

I also tried this:

class MainWindow(QtGui.QWidget):
    def __init__(self, parent=GetMayaMainWindow()):
        QtGui.QWidget.__init__(self, parent)
            [...]

#### register command and connect to UI #####
class scriptedCommand(OpenMayaMPx.MPxCommand):
 def __init__(self):
    OpenMayaMPx.MPxCommand.__init__(self);
 def doIt(self,argList):
    global mainWindow;
    mainWindow = MainWindow();
    deform=Deformer();
    mainWindow.applyAnimSignal.connect(deform.addAnimation)
    mainWindow.show()

This simply closes down Maya all together.

Sorry, but I am a bit lost here. I am used to qt development but have no idea about the connection with maya. Thanks for your help.

whenever I load and start the plugin, maya does not update its scene screen anymore.

well offcourse you just enetered a infinite loop. Which should be ovbvous but for some reason it isnt. So yes either you can juts use teh same message loop as mayas main window. OR then you need to start a separate thread for your own guis message pump. The former is proper as suggested, but you may find doing a second thread conceptualy simpler for your gui code, altough it will suck  for all the maya command code as you would need to split them all to main thread.

You should in fact you should start with something completely and utterly simple, with allmost no functionality first, all the orther code is a just a massive distraction for you at this point. Its quot different to write sandalone applications than just piggyback on other applications.

PS: 2008 is horrible theres no way to fix that!

Thanks for your help guys, but I found the problem.

My code now:

class scriptedCommand(OpenMayaMPx.MPxCommand):
 def __init__(self):
  OpenMayaMPx.MPxCommand.__init__(self);
 def doIt(self,argList):
    global app;
    global mainWindow;
    global deform;

    app=QtGui.qApp
    mainWindow = MainWindow();
    deform=Deformer();

    mainWindow.show()
    app.connect(app, QtCore.SIGNAL("lastWindowClosed()"),app, QtCore.SLOT("quit()"))

Important was to make the app, window and deformer, I use, global so they dont get picked up by the garbage collection. I also did not need the GetMainMayaWindow. QtGui.qApp simply did the trick.

Thanks