Getting keyboard focus of QlineEdit and other issues

Hey everyone,

I’ve been coding pretty heavily the past 10 months ( MEL to Python ), so I think I’m about ready to take the plunge into Qt. It turns out that I’m not that ready because I’m about 3 days into PySide and I’m stuck. I’m trying to make a script that works exactly like the node editor tab creation tool, but instead of only working in the node editor, this script will work anywhere in Maya. Seeing as this is my first PySide script, pretty much all of it so far comes from tutorials and tidbits I’ve found around the internet, so please let me know if I’m doing something wrong or could do something a better way.

Description of what I’d like to accomplish:

  • I’d basically like to create a script that functions like the node editor tab creation mechanism… but it creates objects anywhere in maya
  • Kind of like tab node creation in houdini/nuke
  • The end of this script has some basic working examples of what I want to accomplish and commands that might help me along the way

Issues so far:

  1. I can’t get focus of the QlineEdit window. When the script is run, the cursor shows focus inside the box, but the keyboard focus isn’t there
  2. I’d like to know how to manipulate the thickness of the rectangle box around the QlineEdit window (and/or how to make it so just the QlineEdit field displays without window ornaments)
  3. How can I access the node editor tab creation script so I can see how it works? Like how does it have a list of commands that pop up and how does it match what you’re typing?

from PySide import QtCore 
from PySide import QtGui 
from shiboken import wrapInstance 
from difflib import SequenceMatcher as SM

import traceback
import maya.cmds as mc
import maya.mel as mel
import maya.OpenMayaUI as mui


def maya_main_window():
    ptr = mui.MQtUtil.mainWindow()
    return wrapInstance( long( ptr ), QtGui.QWidget )
    
# UI class
class mb_PandoraUI( QtGui.QDialog):
    
    def __init__( self, parent=maya_main_window() ):
        super( mb_PandoraUI, self ).__init__( parent )
        
    def create( self ):
        '''
        Create the UI
        '''
        self.setWindowTitle( "mb_Pandora" )
        self.setWindowFlags( QtCore.Qt.Tool )
        self.setAttribute( QtCore.Qt.WA_DeleteOnClose )
        
        self.create_controls()
        self.create_layout()
        self.create_connections()

    def resizeEvent(self, event):
        pixmap = QtGui.QPixmap(self.size())
        pixmap.fill(QtCore.Qt.transparent)
        painter = QtGui.QPainter(pixmap)
        painter.setBrush(QtCore.Qt.black)
        painter.drawRoundedRect(pixmap.rect(), 8, 8)
        painter.end()
            
        self.setMask(pixmap.mask())
        self.setAttribute( QtCore.Qt.WA_DeleteOnClose )
        
    def create_controls( self ):
        self.line_edit = QtGui.QLineEdit( parent=self )
        self.line_edit.setObjectName( "pyLineEdit" )
        #self.line_edit.setFrame(False)
        self.line_edit.isActiveWindow()
        self.line_edit.setFocus()
        
    def create_layout( self ):
        main_layout = QtGui.QVBoxLayout()
        main_layout.addWidget( self.line_edit )
        
        self.setLayout( main_layout )
        
        
    def create_connections( self ):
        self.line_edit.textChanged.connect( self.on_text_changed )
        
        
    ##############################################
    ## SLOTS   
    ##############################################
    def on_text_changed(self):
        print("Text changed")
    
if __name__ == "__main__":

    # Development workaround for PySide error (Maya 2014)
    # Make sure the UI is deleted before recreating
    try:
        mb_pandora_ui.close()
        mb_pandora_ui.deleteLater()
    except:
        pass

    # Create minimal UI object
    mb_pandora_ui = mb_PandoraUI()
    
    # Delete the UI if errors occur to avoid causing 
    # and event errors (in Maya 2014)
    try:
        mb_pandora_ui.create()
        mb_pandora_ui.show()
    except:
        mb_pandora_ui.close()
        mb_pandora_ui.deleteLater()
        traceback.print_exc()    

-This code does a very basic version of what I want in the end

      
def mb_runCommand( thing ):
    thing = mel.eval( "{0}".format( command ) )
   
result = mc.promptDialog( title="Create", button=["Create", "Cancel"], cancelButton="Cancel", dismissString="Cancel", m="Watchu wanna dew?" )

if result == "Create":
    # Vars
    createName = mc.promptDialog( q=1 )
    mb_runCommand( createName )

  • autodesk example for the cmdScrollFieldExectuer, which functions similar to how I want the script to work

import maya.cmds as mc

# this will create a tiny window with a Mel command executer.
mc.window()
mc.columnLayout()
mc.cmdScrollFieldExecuter(width=200, height=100, npm=0)
mc.showWindow()

-autodesk stuff that I’m using to test out fuzzy string comparison


s1 = ' It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats.'
s2 = ' It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines.'
match = SM(None, s1, s2).ratio()
print match

-possible was to list commands to fuzzy string compare against


allPossibleNodes = mc.allNodeTypes()
for item in allPossibleNodes:
    print (item)

import maya.cmds as cmds

def printNewMenuItem( item ):
	print item

window = cmds.window()
cmds.columnLayout()
cmds.optionMenu( label='Colors', changeCommand=printNewMenuItem )
cmds.menuItem( label='Yellow' )
cmds.menuItem( label='Purple' )
cmds.menuItem( label='Orange' )
cmds.showWindow( window )

Thank in advance for any and all help!

Best,

Mike

I’ve made a lot of progress with the code in the past week, but there are still some tweaks I’d like to make.

Solutions so far:

  1. I can’t get focus of the QlineEdit window. When the script is run, the cursor shows focus inside the box, but the keyboard focus isn’t there

I fixed this by removing the “self.setWindowFlags( QtCore.Qt.Tool )” line from the code. Not exactly sure why that worked though.

  1. I’d like to know how to manipulate the thickness of the rectangle box around the QlineEdit window (and/or how to make it so just the QlineEdit field displays without window ornaments)

Used this line: “self.main_layout.setContentsMargins(2,2,2,2)” to edit the margin size

  1. How can I access the node editor tab creation script so I can see how it works? Like how does it have a list of commands that pop up and how does it match what you’re typing?

I discovered the QCompleter class which does most of the work for me in terms of providing a list of results that pops up under my QLineEdit field. There’s an example in the PySide documentation that explains how to use QCompleter in tandem with the QLineEdit widget. The only problem with this technique is that I don’t really have any control of the search rules (other than case sensitivity).

Wishlist:

  1. I have the script working, but as I mentioned before, the UX is not as flowy as I’d like it. Ideally I’d like to get fuzzy string matching to work, so if I type “cbue”, I’d still get results that have the string “cube” in them.
    If that’s not possible I’d settle for a string matching workflow. Where if I typed “cube”, any command with the string “cube” in it would be displayed. Here’s a general explanation of what I want to achieve, with some answer examples: link

I’m currently trying to get some of that threads’ answers to work in Maya, but I’m not sure how to visualize a “model view” programmed script with maya. I’ll be doing these tutorials this weekend: link to see if that can answer my questions, but any tip/pointers until then would help a ton.

  1. Make the code more efficient. I’m sure it looks like a complete mess to any experience Qt programmer, so any suggestions on how to clean it up would be great