04.21
Re-posting some information here that I had posted on TD club:
import maya.OpenMayaUI as mui import PyQt4.QtCore as QtCore import PyQt4.QtGui as QtGui import sip def getMayaWindow(): #Get the maya main window as a QMainWindow instance ptr = mui.MQtUtil.mainWindow() return sip.wrapinstance(long(ptr), QtCore.QObject) class MayaSubWindow(QtGui.QMainWindow): 'My custom window, which i want to parent to the maya main window' def __init__(self, parent=getMayaWindow()): #Init my main window, and pass in the maya main window as it's parent QtGui.QMainWindow.__init__(self, parent) #Show my window myWindow = MayaSubWindow() myWindow.show()
Here’s a quick little bit of code showing how to create a custom GUI class using pyqt (Almost all the pyqt examples use this over using some form of .ui file, because it allows for much more control). You can also use it in combination with ui files thanks to pyqt’s uic module.
QT does not require objects to have “names”, but if you ever want to find your pyqt objects using MQtUil.findControl then you need to assign it a name using OBJECT.setObjectName(“AwesomeWindow”). In the above example, in the MayaSubWindow.__init__ function you would call self.setObjectName(“AwesomeWindow”).
Also, since qt does not require names, it also does not require that control names be unique, so it’s completely possible to use findControl and get the “wrong” object. So you may want to ensure that the name you are using is unique if you want to use it to find that object again later. (Also, you can skip the whole findControl step by just using instance variables to keep track of all your controls, like what the pyqt examples use)
Here’s a pyqt example using uic to load in a ui file (Rather than maya’s new loadUi command, which wont give you all your pyqt objects.
import os import sip import maya.cmds as cmds import maya.OpenMayaUI as mui from PyQt4 import QtGui, QtCore, uic def getMayaWindow(): 'Get the maya main window as a QMainWindow instance' ptr = mui.MQtUtil.mainWindow() return sip.wrapinstance(long(ptr), QtCore.QObject) #Get the absolute path to my ui file uiFile = os.path.join(cmds.internalVar(upd=True), 'ui', 'demo.ui') print 'Loading ui file:', os.path.normpath(uiFile) #Load the ui file, and create my class form_class, base_class = uic.loadUiType(uiFile) class Window(base_class, form_class): def __init__(self, parent=getMayaWindow()): '''A custom window with a demo set of ui widgets''' #init our ui using the MayaWindow as parent super(base_class, self).__init__(parent) #uic adds a function to our class called setupUi, calling this creates all the widgets from the .ui file self.setupUi(self) self.setObjectName('myWindow') self.setWindowTitle("My Qt Demo Window") def main(): global myWindow myWindow = Window() myWindow.show()
The python code will look for the ui file in maya2011\prefs\ui\demo.ui. It will print a message with the absolute path when running.
This is great, but I can’t for the life of me figure out how to load a UI file’s QMenu directly into the Maya menu bar. Any ideas?
I have a stripped down UI file that only contains QMainWindow >> QMenuBar and various QMenus with their associated QActions. No buttons or anything like that—just menu stuff.
At the end of the day I’m trying to have myself a UIMenu and UIDocker class that handle all the UI file initialization on the fly. That way, I can create a series of dockers and menus for Maya with ease, never having to deal with the code you have above more than once.
That’s the idea, anyway. I got my dockers working fine, but the menus are proving to be difficult!
Nathan, this is great reference, it’s been very helpful and fast to be able to get Designer .ui files in Maya 2012. I really appreciate the help. I have a question though, how would you use a second .ui file as a second window which pops up from a button on the first window?
…nevermind Nathan, I was able to figure this out once I understood that uic.loadtype() was generating the two necessary classes for inheritance into my UI class. I’m new to writing classes and using class inheritence. Thanks for you time, and thanks for the code reference.
Never mind my previous comment… I downloaded the latest version of PyQt x64 for Python 2.6 and it worked. Something very strange was happening before that!
I was working on some Maya tools for our studio and found this to be an excellent starting point for using PyQt with Maya.
I was wondering if you had a reliable and simple method to make sure that only one copy of your window is open at once? We use the shelf to launch scripts and usually in the script we will check if the window exists, close it if it does, and then load the UI. It would be great to be able to duplicate this functionality with PyQt interfaces, but I can’t seem to find a good way to do it.
Any help would be greatly appreciated!
I always create a simple main() or showUi() function that stores the window into a variable. Before creating a new instance first try to close the previous one.
EX:
def main():
global win
try:
win.close()
except: pass
win = MyWindowClass()
win.show()