removing duplicates from QListWidget

1,091 views
Skip to first unread message

vilkdage

unread,
Nov 12, 2017, 3:34:57 PM11/12/17
to Python Programming for Autodesk Maya


Hi guys,
I am writing a tool to ease transfer of skin weights between objects and pruning them. I already have GUI written down. I am stilling figuring out how to implement QFrame correctly, but I have a bit bigger dragon to slay for a moment.
I used QListWidget to store selected items, but I am stuck at figuring out the logic how to remove duplicated items from widget if user keeps on adding same items to the list. How should I go about this problem?

from PySide2 import QtWidgets, QtCore, QtGui
from shiboken2 import wrapInstance
from maya import OpenMayaUI as omui
import pymel.core as pm

def getMayaMainWindow():
    win
= omui.MQtUtil_mainWindow()
    ptr
= wrapInstance(long(win), QtWidgets.QMainWindow)
   
return ptr

def getDock(name="CopySkinWeightsDsock"):
    deleteDock
(name)
    ctrl
= pm.workspaceControl(name, dockToMainWindow=("left", 1), label="Copy Skin Weight Manager")
    qtCtrl
= omui.MQtUtil_findControl(ctrl)
    ptr
= wrapInstance(long(qtCtrl), QtWidgets.QWidget)
   
return ptr

def deleteDock(name="CopySkinWeightsDsock"):
   
if pm.workspaceControl(name, query=True,exists=True):
        pm
.deleteUI(name)

class transferSkinWeightUI(QtWidgets.QWidget):
   
"""
    The transferSkinWeightUI let us transfer skin weights from one object to another
    """

   
def __init__(self, dock = True):
       
if dock:
            parent
= getDock()
       
else:
            deleteDock
()

            parent
= QtWidgets.QDialog(parent=getMayaMainWindow())
            parent
.setObjectName("skinningManager")
            parent
.setWindowTitle("Copy Skin Weight Manager")
            layout
= QtWidgets.QVBoxLayout(parent)

       
super(transferSkinWeightUI, self).__init__(parent = parent)
       
self.buildUI()
       
self.parent().layout().addWidget(self)
       
if not dock:
            parent
.show()

   
def buildUI(self):
       
""" This method builds out the UI """
       
# This is the master layout
        mainLayout
= QtWidgets.QVBoxLayout(self)

        tableWidget
= QtWidgets.QWidget()
        tableWidget
.setObjectName("centralwidget")
        tableLayout
= QtWidgets.QHBoxLayout(tableWidget)
        mainLayout
.addWidget(tableWidget)

       
# SOURCE W info
        sourceInfoWidget
= QtWidgets.QWidget()
        sourceInfoLayout
= QtWidgets.QVBoxLayout(sourceInfoWidget)
        tableLayout
.addWidget(sourceInfoWidget)

        sourceLabel
= QtWidgets.QLabel("Source Geo")
        sourceInfoLayout
.addWidget(sourceLabel)

       
# This will create a grid widget to display our selected items
       
self.sourceWidget = QtWidgets.QListWidget()
       
self.sourceWidget.setViewMode(QtWidgets.QListWidget.ListMode)
        sourceInfoLayout
.addWidget(self.sourceWidget)

        sourceButtonWidget
= QtWidgets.QWidget()
        sourceButtonLayout
= QtWidgets.QHBoxLayout(sourceButtonWidget)
        sourceInfoLayout
.addWidget(sourceButtonWidget)

        selectSourceBtn
= QtWidgets.QPushButton("Import")
        selectSourceBtn
.clicked.connect(self.populateSourceItems)
        sourceButtonLayout
.addWidget(selectSourceBtn)

        deselectSourceBtn
= QtWidgets.QPushButton("Delete")
        deselectSourceBtn
.clicked.connect(self.deleteSourceItems)
        sourceButtonLayout
.addWidget(deselectSourceBtn)

       
# POST W info
        postInfoWidget
= QtWidgets.QWidget(tableWidget)
        postInfoLayout
= QtWidgets.QVBoxLayout(postInfoWidget)
        tableLayout
.addWidget(postInfoWidget)

        postLabel
= QtWidgets.QLabel("Post Geo")
        postInfoLayout
.addWidget(postLabel)

       
# This will create a grid widget to display our selected items
       
self.postWidget = QtWidgets.QListWidget()
       
self.postWidget.setViewMode(QtWidgets.QListWidget.ListMode)
        postInfoLayout
.addWidget(self.postWidget)

        postButtonWidget
= QtWidgets.QWidget()
        postButtonLayout
= QtWidgets.QHBoxLayout(postButtonWidget)
        postInfoLayout
.addWidget(postButtonWidget)

        selectPostBtn
= QtWidgets.QPushButton("Import")
        selectPostBtn
.clicked.connect(self.populatePostItems)
        postButtonLayout
.addWidget(selectPostBtn)

        deselectPostBtn
= QtWidgets.QPushButton("Delete")
        deselectPostBtn
.clicked.connect(self.deletePostItems)
        postButtonLayout
.addWidget(deselectPostBtn)

       
# holds bottom buttons
        bottomWidget
= QtWidgets.QWidget()
        bottomLayout
= QtWidgets.QHBoxLayout(bottomWidget)
        mainLayout
.addWidget(bottomWidget)

        transferBtn
= QtWidgets.QPushButton("Transfer")
        bottomLayout
.addWidget(transferBtn)

        applyBtn
= QtWidgets.QPushButton("Apply")
        bottomLayout
.addWidget(applyBtn)

        closeBtn
= QtWidgets.QPushButton("Close")
        closeBtn
.clicked.connect(self.close)
        bottomLayout
.addWidget(closeBtn)

   
def populateSourceItems(self):
        sourceItems
= pm.ls(sl=1)

       
# items currently listed in QListWidget
        lst
= [i.text() for i in self.sourceWidget.findItems("", QtCore.Qt.MatchContains)]

       
for i in sourceItems:
            item
= QtWidgets.QListWidgetItem("%s" % i)
           
self.sourceWidget.addItem(item)

   
def populatePostItems(self):
        postItems
= pm.ls(sl=1) # to which items
       
for i in postItems:
            item
= QtWidgets.QListWidgetItem("%s" % i)
           
self.postWidget.addItem(item)

   
def transferWeights(self): pass

   
def deleteSourceItems(self):
        item
= self.sourceWidget.takeItem(self.sourceWidget.currentRow())

   
def deletePostItems(self):
        item
= self.postWidget.takeItem(self.postWidget.currentRow())

Justin Israel

unread,
Nov 12, 2017, 4:05:53 PM11/12/17
to python_in...@googlegroups.com
Just a note for future posts. If you are going to post this much code can you please use a gist or a pastebin?

I would recommend just using something like a findItems() to check for any existing values in your QListWidget, and then only adding the ones that aren't matching. I see you already have a call to findItems(). Are you having an issue with looking up existing values by text?

Justin


On Mon, Nov 13, 2017 at 9:35 AM vilkdage <vilk...@gmail.com> wrote:

vilkdage

unread,
Nov 12, 2017, 4:17:16 PM11/12/17
to Python Programming for Autodesk Maya
my apologies, is there a way I can edit original post?

Yes, that is a problem. I would not have it if I used cmds, but PyMel throws back and node type which makes it impossible to compare values between what i am getting from findItems() and pm.ls(sl=1) unless I were to remove the first part of each string which tells nodetype. I also would not have this kind of problem if I used maya API, but I am not familiar with its syntax.

Is the best solution to remove nodetype from what pm.ls(sl=1) gives me?

Justin Israel

unread,
Nov 12, 2017, 4:36:26 PM11/12/17
to python_in...@googlegroups.com
On Mon, Nov 13, 2017 at 10:17 AM vilkdage <vilk...@gmail.com> wrote:
my apologies, is there a way I can edit original post?

I think only moderators (myself) can edit posts. But no reason to do it as this point since many people already received it via email. 
 

Yes, that is a problem. I would not have it if I used cmds, but PyMel throws back and node type which makes it impossible to compare values between what i am getting from findItems() and pm.ls(sl=1) unless I were to remove the first part of each string which tells nodetype. I also would not have this kind of problem if I used maya API, but I am not familiar with its syntax.

Is the best solution to remove nodetype from what pm.ls(sl=1) gives me?

Lets just look at this snippet specifically:

    def populateSourceItems(self):
        sourceItems = pm.ls(sl=1)

        # items currently listed in QListWidget
        lst = [i.text() for i in self.sourceWidget.findItems("", QtCore.Qt.MatchContains)]

        for i in sourceItems:
            item = QtWidgets.QListWidgetItem("%s" % i)
            self.sourceWidget.addItem(item)

You have full control over what value from your PyMel objects that you want to add to your widget. So it shouldn't matter if its the cmds module, PyMel, the API, or whatever. You just have to choose if you are going to convert it to a string, or specifically use the shortName() vs longName(). If you are currently just dumping all of the list values, why not check if you already have it in the list before adding it?

        # items currently listed in QListWidget

        existing = set(i.text() for i in self.sourceWidget.findItems("", QtCore.Qt.MatchContains))

        for i in sourceItems:
            text = str(i)
            if text in existing:
                continue
            item = QtWidgets.QListWidgetItem(text)
            item.setData(QtCore.Qt.UserRole, i)
            self.sourceWidget.addItem(item)
 As you can see, you could also store the PyMel node on the item so that it could be retrieved later via  item.data(QtCore.Qt.UserRole)

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/2efd9ddf-1f61-4b4b-8c44-86191a81d8ec%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

vilkdage

unread,
Nov 12, 2017, 5:23:06 PM11/12/17
to Python Programming for Autodesk Maya
amazing! At first I tried going through both list with zip() to find differences. That's where I failed.
I must say that UserRole is something I have not heard about thus far. I will have to look into it. Thank you very much for teaching me!

Justin Israel

unread,
Nov 12, 2017, 5:26:51 PM11/12/17
to python_in...@googlegroups.com
On Mon, Nov 13, 2017 at 11:23 AM vilkdage <vilk...@gmail.com> wrote:
amazing! At first I tried going through both list with zip() to find differences. That's where I failed.
I must say that UserRole is something I have not heard about thus far. I will have to look into it. Thank you very much for teaching me!

Just in case the docs aren't clear about this, UserRole is the starting value for any custom roles you want to store. Qt owns the values below that point for stuff like DisplayRole, DecorationRole, and so on. So you can store arbitrary amounts of extra data with your items with a pattern like this:

PyMelNodeRole = QtCore.Qt.UserRole
OtherDataRole = QtCore.Qt.UserRole+1

def func():
    ...
    item.setData(PyMelNodeRole, node)
    data = item.data(OtherDataRole)
 

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages