I recently noticed that one of my PyQt-based Maya tools was introducing a noticeable lag into Maya. Not so much that you’d notice if you only ran the tool once or twice but definitely there if you ran it 10-20 times or more.
My first thought was maybe I was doing something weird to the system memory but that was easy to eliminate. Next, I used cProfile to see if any particular function or method was causing a bottleneck. Usually cProfile is pretty good about identifying the slow stuff but, in this case, failed to reveal the culprit. Could it be that whatever was slowing down Maya was acting outside of my tool?
If you think about it, there are plenty of ways to introduce changes to the Maya environment that may end up causing a lag. In my case, after a bit more searching, I realized that the eventFilter I installed everytime my tool launched was not getting deleted on close.
For those who don’t know, an eventFilter is exactly what it sounds like: a way for the developer to filter through (Py)Qt events before they reach their designated event handlers. Further, installing an eventFilter on the QApplication level makes it possible to filter every single event. That means if you want to modify how all widgets (or all widgets of a particular type) handle any event, you can easily do so. You can also decide whether an event should even be processed.
In my case, I was using the eventFilter to disable all wheelEvents from reaching QComboBoxes so that using the mouse wheel when hovering over a combo box wouldn’t change its value. If you’re interested, the code to do so is very simple:
def __init__(self, parent=getMayaWindow()):
def eventFilter(self, obj, event):
Event filter for rerouting wheelEvents away from combo boxes.
if event.type() == QtCore.QEvent.Wheel and isinstance(obj, QtGui.QComboBox):
#this handles all the wheel events for the combo boxes
return super(MyTool, self).eventFilter(obj, event)
Unfortunately, closing the tool did not remove the eventFilter. Plus, every time I relaunched the tool, I was installing another instance of the exact same filter. No wonder Maya was getting bogged down! Every Qt event was being run through 20 of these!
The solution was very simple. All I had to do was remove the eventFilter when my tool was closed, which I did via closeEvent:
def closeEvent(self, e):
Make sure the eventFilter is removed
return super(LightKitEditor, self).closeEvent(e)
This was far from the first time that I had used eventFilters in my tools and I was understandably curious why I hadn’t noticed any slowdowns before. Turns out, I was calling self.deleteLater from their closeEvents, which was deleting their eventFilters and removing them from the Maya application. This made sense since simply closing the tool window would not be enough to invoke garbage collection in Python if the application’s event filter list still had a reference to the eventFilter function.