Hi,
Am writing a renaming tool for maya. Its almost done but Im stuck on a issue.
I’m following Rob’s book “Practical Maya Programming with Python”. So I’m keeping the Qt(PySide) code seperate from my maya code.
Here’s a quick laydown:
#The window contains two list widgets (old names, new names) and two buttons (load objects, rename objects). Old names list is not editable.
The UI is made with Qt Designer and converted to python using pysideuic.
The way its supposed to work:
- Click “Load Objects” button to load selected objects(names) on both list widgets.
- User edits the text on the “new names” list widget.
- Click the “Rename Objects” button to rename objects on the “old names” widget with the naming from the “new names” widget.
It works the first time. After that, I get this error:
RuntimeError: Internal C++ object (PySide.QtGui.QListWidgetItem) already deleted.
I create the QListWidgetItem in the loop as I want the “new names” list to be editable. I can
understand qt/python clearing it as garbage collection. How can I create the QListWidgetItem properly so it doesn’t get cleared on refresh.
Can someone help me understand and write this efficiently so I can keep the list editable and
refresh/recreate the QListWidgetItem on each object load. What I’ve written is quite crude.
The ui file(converted to python) is attached with this post.renameTest.zip (1.1 KB)
Here’s the extracted code: (It also contains a test function so you can test-run it with mayapy on a console)
from qtshim import QtGui, QtCore, Signal
from renameTest import Ui_MainWindow as rePy
class RenamerController(QtCore.QObject):
objList = Signal(list)
class RenamerWindow(QtGui.QMainWindow):
customRenameClicked = Signal(list, list)
loadObjsClicked = Signal(list)
class Renamer(RenamerWindow):
def __init__(self, controller, parent=None, ):
super(Renamer, self).__init__(parent)
self.ui = rePy()
self.ui.setupUi(self)
self.ui.load_objs_btn.clicked.connect(self.oncommit)
self.ui.custom_rename_btn.clicked.connect(self.oncommit)
controller.objList.connect(self.update_loaded_objs)
self.newList = []
def oncommit(self):
sender = self.sender().objectName()
if sender == 'load_objs_btn':
self.loadObjsClicked.emit('')
elif sender == 'custom_rename_btn':
old_list = []
for index in xrange(self.ui.loaded_objs_list.count()):
text = self.ui.loaded_objs_list.item(index).text()
old_list.append(text)
new_list = []
for item in self.newList:
new_list.append(item.text())
self.customRenameClicked.emit(old_list, new_list)
def update_loaded_objs(self, load_objs):
self.ui.loaded_objs_list.clear()
self.ui.loaded_objs_list.addItems(load_objs)
self.ui.preview_new_names_list.clear()
for obj in load_objs:
obj = QtGui.QListWidgetItem(obj)
obj.setFlags(QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable |
QtCore.Qt.ItemIsEnabled)
self.ui.preview_new_names_list.addItem(obj)
self.newList.append(obj)
def _pytest():
controller = RenamerController()
def objs_list():
selected_objs = (
'pSphere1',
'pCube1',
'polyCube1',
'nurbsCircle'
)
return selected_objs
def load_objs():
controller.objList.emit(objs_list())
def custom_rename(old_list, new_list):
for i in range(len(old_list)):
print '%s renamed to %s' % (old_list[i], new_list[i])
app = QtGui.QApplication([])
win = Renamer(controller)
win.loadObjsClicked.connect(load_objs)
win.customRenameClicked.connect(custom_rename)
win.show()
app.exec_()
if __name__ == '__main__':
_pytest()
I’ve tried to be as clear as possible.