dissidia dissidia - 1 month ago 14
Python Question

Check row by row in QTableWidget to affect QCombobox

I have a QTableWidget, 2 Columns in which the first column contains the name of items while the second column is populated with qcomboboxes (created using cellwidgets) which contains a list of color options (eg. "", RED, BLUE, GREEN)

For example, in the following table, items denoted with * has a variable called

color_set
, I am trying to achieve as follows:


  • it will lookup the names of items in the scene

  • then it will go through a function to check and see if the item
    shirt_01
    contains a variable called
    color_set

  • If the variable exists, say if it is RED, it will then lookup the list of options in the combobox and display RED as the value

  • If the variable does not exists, it will displays a blank field instead

  • this function/values populate the table with information before the ui is launched, it is not a button clicked function etc.

    Name of items | Color Options
    shirt_01* | RED
    shirt_02 |
    pants* | GREEN



However, instead of getting my ui to output as above, I got the following result:

Name of items | Color Options
shirt_01* | RED
shirt_02 | RED
pants* | GREEN


For some reasons, the
shirt_02
seems to got 'tangled' and displayed the same result as
shirt_01
. And I think it could possibly be due to how my logic was written but I could not figure it out or because I keep tying my output result to
self.color_combobox
as my code initially checks through the first column then find the matching text in the second column.
But I keep getting error at the line - item_name has no attribute .text()

import maya.cmds as cmds
from PyQt4 import QtGui, QtCore
import json

def get_all_mesh():
all_mesh = cmds.listRelatives(cmds.ls(type = 'mesh'), parent=True)
return all_mesh

def read_json(node_name):
# checks if the node_name exists in the json file
with open('/Desktop/car_colors.json') as data_file:
data = json.load(data_file)

items = set()
for index, name in enumerate(data):
# if the name is in the json, it will states the color
if node_name in name:
for item in (data[name]):
#print "{0} - {1}".format(name, item)
items.add(item)
return items

def attrToPy(objAttr):
stringAttrData = str(cmds.getAttr(objAttr))
loadedData = cPickle.loads(stringAttrData)

return loadedData


class testTableView(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('Color Test')
self.setModal(False)

self.all_mesh = get_all_mesh()

# Build the GUI
self.init_ui()
self.populate_data()


def init_ui(self):
# Table setup
self.mesh_table = QtGui.QTableWidget()
self.mesh_table.setRowCount(len(self.all_mesh))
self.mesh_table.setColumnCount(3)
self.mesh_table.setHorizontalHeaderLabels(['Mesh Found', 'Color for Mesh'])
self.md_insert_color_btn = QtGui.QPushButton('Apply color')

# Layout
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.mesh_table)
self.layout.addWidget(self.md_insert_color_btn)
self.setLayout(self.layout)

def populate_data(self):
geo_name = self.all_mesh

for row_index, geo_item in enumerate(geo_name):
new_item = QtGui.QTableWidgetItem(geo_item)
# Add in each and every mesh found in scene and append them into rows
self.mesh_table.setItem(row_index, 0, new_item)

geo_exclude_num = ''.join(i for i in geo_item if not i.isdigit())
color_list = read_json(geo_exclude_num)

color_list.add("")
# Insert in the color
self.color_combobox = QtGui.QComboBox()
#color_list = get_color()
self.color_combobox.addItems(list(sorted(color_list)))
self.mesh_table.setCellWidget(row_index, 1, self.color_combobox)
self.color_value_to_combobox()

def color_value_to_combobox(self):
obj_nodes = get_all_mesh()
for node in obj_nodes:
# This attribute is stored in the Extra Attributes
objAttr = '%s.pyPickle'%node
storedData = attrToPy(objAttr)

if 'color_set' in storedData:
color_variant = storedData['color_set']
combo_index = self.color_combobox.findText(color_variant, QtCore.Qt.MatchFixedString)
self.color_combobox.setCurrentIndex(0 if combo_index < 0 else combo_index)


# To opent the dialog window
dialog = testTableView()
dialog.show()


Is there anyway in which I can make my ui to check for the list of item in scene, tallies which name and combobox it should go (in terms of which rows/columns)? Otherwise what other ways can i approach?

EDIT: This is the attachment that I did it quick - Link
If you run the UI, you will notice that pCube1 has the color "red" while pCube2 is "blue", however both the comboboxes will turn up as blue instead

Answer

Ok, so the problem was in color_value_to_combobox. Instead of setting the combobox for ALL objects, you need to specify what object and combobox the function needs to work on. The major flaw was that you were using self.color_combobox to set with every time, so every object would keep setting the same combobox! It needs to be more generic. Instead of storing the combobox to self.color_combobox I would normally store it in a list, otherwise you can't access all of them anymore, but I leave that to you.

Anyways, I just had to change the end of populate_data and color_value_to_combobox. Now cube1 shows red, and cube2 shows blue.

import maya.cmds as cmds
from PyQt4 import QtGui, QtCore
import json
import cPickle

def get_all_mesh():
    all_mesh = cmds.listRelatives(cmds.ls(type = 'mesh'), parent=True)
    return all_mesh

def read_json(node_name):
    # checks if the node_name exists in the json file
    with open('/Desktop/car_colors.json') as data_file:
        data = json.load(data_file)

        items = set()
        for index, name in enumerate(data):
            # if the name is in the json, it will states the color
            if node_name in name:
                for item in (data[name]):
                    #print "{0} - {1}".format(name, item)
                    items.add(item)
    return items

def attrToPy(objAttr):
    stringAttrData = str(cmds.getAttr(objAttr))
    loadedData = cPickle.loads(stringAttrData)

    return loadedData


class testTableView(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)
        self.setWindowTitle('Color Test')
        #self.setModal(False)

        self.all_mesh = get_all_mesh()

        # Build the GUI
        self.init_ui()
        self.populate_data()


    def init_ui(self):
        # Table setup
        self.mesh_table = QtGui.QTableWidget()
        self.mesh_table.setRowCount(len(self.all_mesh))
        self.mesh_table.setColumnCount(3)
        self.mesh_table.setHorizontalHeaderLabels(['Mesh Found', 'Color for Mesh'])
        self.md_insert_color_btn = QtGui.QPushButton('Apply color')

        # Layout
        self.layout = QtGui.QVBoxLayout()
        self.layout.addWidget(self.mesh_table)
        self.layout.addWidget(self.md_insert_color_btn)
        self.setLayout(self.layout)

    def populate_data(self):
        geo_name = self.all_mesh

        for row_index, geo_item in enumerate(geo_name):
            new_item = QtGui.QTableWidgetItem(geo_item)
            # Add in each and every mesh found in scene and append them into rows
            self.mesh_table.setItem(row_index, 0, new_item)

            geo_exclude_num = ''.join(i for i in geo_item if not i.isdigit())
            color_list = read_json(geo_exclude_num)

            color_list.add("")
            # Insert in the color
            color_combobox = QtGui.QComboBox()
            #color_list = get_color()
            color_combobox.addItems(list(sorted(color_list)))
            self.mesh_table.setCellWidget(row_index, 1, color_combobox)

            self.color_value_to_combobox(geo_item, color_combobox) # Pass the object and combobox you want to set

    # This use to work on all mesh objects, but only edits a single combobox. This is wrong!
    def color_value_to_combobox(self, node, combobox):
        # This attribute is stored in the Extra Attributes
        objAttr = '%s.pyPickle'%node
        storedData = attrToPy(objAttr)

        if 'color_set' in storedData:
            color_variant = storedData['color_set']
            combo_index = combobox.findText(color_variant, QtCore.Qt.MatchFixedString)
            combobox.setCurrentIndex(0 if combo_index < 0 else combo_index) # Needs to work on the proper combobox!


# To opent the dialog window
dialog = testTableView()
dialog.show()