Confirm my suspicions

I’m reasonably sure this is true - but just in case:

Is it true there’s no way to catch invidual keypresses in a maya text control (eg, a textField)? I’d like to do a progressive search filter that updates as the user types - but AFAIK there’s no way to catch individual characters as the user types: you only get change events when the user hits enter, return, or the field loses focus.

Or am I missing something?

I don’t think that’s possible with a textField, but you could use a scrollField with keyPressCommand :):

You want the textFieldGrp textChangedCommand flag, it means that as you type you can fire a callback. I use it in the Red9 PoseUI so the guys can interactively filter the pose lists without having to hit bloody enter all the time, only available from 2013 onwards though

Mark

not sure if it would work as I haven’t played with maya in a awhile, but why don’t you just run a loop that grabs the input of the field every half second or so? It might be a little laggy, but it seems like this might work. (as a hack)

I’m sort of screwed for the time being, as I’m on 2011 so Mark’s suggestion won’t work. The background loop won’t either, since you can’t access GUI elements from outside the main thread (and doing it in the main thread would prevent typing… I know 'cuz I tried :slight_smile: ) scrollField works, although a 1 line scroll field still keeps it’s scroll bar. sigh

Thanks guys

If you have PyQt available on the machines you’re deploying to then you could use it to get a handle to the underlying QLineEdit object for the textField and hook into the textChanged signal.

Using Nathan Horne’s toQtObject method:


import maya.cmds as cmds
import maya.OpenMayaUI as apiUI
from PyQt4 import QtCore
import sip

# From Nathan Horne: http://nathanhorne.com/?p=381
def toQtObject(mayaName):
    '''
    Given the name of a Maya UI element of any type,
    return the corresponding QWidget or QAction.
    If the object does not exist, returns None
    '''
    ptr = apiUI.MQtUtil.findControl(mayaName)
    if ptr is None:
        ptr = apiUI.MQtUtil.findLayout(mayaName)
    if ptr is None:
        ptr = apiUI.MQtUtil.findMenuItem(mayaName)
    if ptr is not None:
        return sip.wrapinstance(long(ptr), QtCore.QObject)

# A bit of the maya cmds textField exanple window
win = cmds.window()
cmds.rowColumnLayout(numberOfColumns=2, columnAttach=(1, 'right', 0), columnWidth=[(1, 100), (2, 250)])
cmds.text(label='Name')
tfName = cmds.textField()
cmds.showWindow(win)

# Callback function (will be used as a Qt slot)
def doStuffWithText(txtQobj):
    print str(txtQobj)

# Get QLineEdit from the Maya UI path string
lineEdit = toQtObject(tfName)
# Connect the textChanged signal
lineEdit.textChanged.connect(doStuffWithText)

Looks pretty heavy handed as an example :wink: but once all the library stuff is in place it’s just the last two lines.

have used the same here more or less.
seems to work fine on 2011, although I wrap to QLineEdit rather than QObject - the latter doesnt have the textchanged signal.

Actually, sip.wrapinstance will return you the best fitting subclass, so in my example you still get a QLineEdit instance back. That’s one of the nice things about sip vs shiboken. You can keep it generic by giving it a base class and let it do the work of finding the right type for you from there.

hmm I assumed it would (as it does in 2013), however in 2011 i was getting an error that QWidget had no such attribute?
I’ll double check tonight - could just be something I’ve missed my side.

Cheers

That is strange. It returns a QLineEdit correctly for me in 2013 and 2011.

[QUOTE=Theodox;23054]I’m reasonably sure this is true - but just in case:

Is it true there’s no way to catch invidual keypresses in a maya text control (eg, a textField)? I’d like to do a progressive search filter that updates as the user types - but AFAIK there’s no way to catch individual characters as the user types: you only get change events when the user hits enter, return, or the field loses focus.

Or am I missing something?[/QUOTE]

Once you have your QtObject of the text field, you can install an eventFilter onto the textField.
In the event filter, you can process pretty much anything:
http://pyqt.sourceforge.net/Docs/PyQt4/qevent.html

qtInstanceOfTextField.installEventFilter(self)

Example of eventFilter:

def eventFilter(self, watched, event, data=''):
	if event.type() == QEvent.KeyPress:
		if event.key() == Qt.Key_Delete:
			if watched.objectName() == 'someName':
				print 'Do stuff'
		elif Qt.Key_Exclam <= event.key() <= Qt.Key_ydiaeresis:
			if watched.objectName() == 'fileList_stringFilter_fld':
				print 'Doing stuff'
		elif event.key() == Qt.Key_Backspace:
			if watched.objectName() == 'fileList_stringFilter_fld':
				print 'Do something'
		elif event.type() == Qt.CopyAction:
			if watched.objectName() == 'fileActions':
				print 'Doing stuff'
						
		return False

The event filter is super useful IMO. You can implement hover, press and mouse move states through the event filter on custom widgets (just remember to set self.setMouseTracking(True))

/Christian

yeah still receiving

AttributeError: ‘QObject’ object has no attribute ‘textChanged’ # using your example in 2011.

apiUI.MQtUtil.findControl is giving QWidget.

I’ll check what it should be getting at work.