2016-10-18 34 views
0

我有一個QTableWidget,第2列第一列包含項目名稱,第二列填充了qcomboboxes(使用cellwidgets創建),其中包含顏色選項列表(如:「」,紅色,藍色,綠色)在QTableWidget中逐行檢查以影響QCombobox

例如,下面的表中,項目帶*有一個變量,名爲color_set表示,我想實現如下:

  • 它會查找場景中物品的名稱
  • 那麼它會通過一個函數來檢查一個d見,如果該項目 shirt_01含有一種叫color_set
  • 如果變量存在變量,說,如果是紅色,它就會查找在下拉列表選項列表,並顯示紅色作爲價值
  • 如果該變量不存在,它會顯示一個空白的領域,而不是
  • 這個函數/值填充信息表推出的UI之前,它不是一個按鈕,點擊等功能

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

然而,不是如上讓我的用戶界面輸出,我得到了以下結果:

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

對於一些原因,shirt_02似乎得到了「糾結」,並顯示相同的結果shirt_01。我認爲這可能是由於我的邏輯是如何編寫的,但我無法弄清楚,或者因爲我的代碼最初檢查第一列,然後在第二列中找到匹配的文本,所以我始終將我的輸出結果綁定到self.color_combobox。 但我一直在該行收到錯誤 - ITEM_NAME有沒有屬性的.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() 

反正在我可以讓我的用戶界面,以檢查現場物品的清單,其中吻合名稱和ComboBox它應該去(根據哪些行/列)?否則,我可以採取哪些其他方式?

編輯:這是我做到了快速的附件 - Link 如果您運行的UI,你會發現,pCube1具有「紅色」,而pCube2爲「藍色」,但無論是組合框會轉動起來的藍色代替

回答

1

好的,所以問題出在color_value_to_combobox。您不需要爲所有對象設置組合框,您需要指定該功能需要處理的對象和組合框。主要缺點是你每次都使用self.color_combobox進行設置,所以每個對象都會保持設置相同的組合框!它需要更通用。我只是不得不改變populate_datacolor_value_to_combobox的結束。現在cube1顯示爲redcube2顯示爲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() 
+0

實際上,使用'self.color_combobox'完全沒有區別,因爲它不斷重置。真正的缺陷是'color_value_to_combobox'中額外的for-loop。最簡單的方法是將'color_value_to_combobox'的前三行註釋掉,並將'node'改爲'geo_item'。換句話說,把它放在一個for循環中,就像我在我的答案中所做的那樣;-) – ekhumoro

+0

他正在遍歷'color_value_to_combobox'中的所有對象,並將該值設置爲相同的組合框'self.color_combobox'。事實上,在他循環遍歷'populate_data'和'color_value_to_combobox'中的所有對象之前,這是毫無意義的。我們基本上做了同樣的回答。你只是合併了兩個函數,這很好,而我只是做了函數需要參數來指定對象和組合框。我用他提供的文件測試了這個例子,它確實有效。 –

+0

@GreenCell你的代碼適用於我的情況,謝謝。我得到了這樣的暗示,這與我創建的'self.color_combobox'有關,因爲我一直在調用在我的代碼中使用的相同的東西。只是不知道如何解決它。 – dissidia

0

如果你看看你發佈的代碼,它不會顯示循環遍歷行將組合框放在每個單元格中,但我會假設有一個,否則它根本無法工作。

你應該做的是以下兩件事之一: - 如果你有一個單獨的循環來創建組合框,那麼在該循環中,如果該項目沒有顏色,則不創建組合框;然後在第二個循環中檢查單元格是否有組合框,並且只有在確實配置它時才檢查。 - 第二個選項是將第一個循環移動到行循環中,即您循環遍歷每一行,以確定項目是否具有顏色,並且只有在這樣做時,才創建組合框並對其進行配置;如果沒有顏色,只是讓賣空。

1

如果顏色變量不存在,你的代碼需要的顏色組合明確地設置爲空項:

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) 

     # This attribute is stored in the Extra Attributes 
     objAttr = '%s.pyPickle' % geo_item 
     storedData = attrToPy(objAttr) 

     if 'color_set' in storedData: 
      color_variant = storedData['color_set'] 
     else: 
      color_variant = '' 

     combo_index = color_combobox.findText(color_variant, QtCore.Qt.MatchFixedString) 
     color_combobox.setCurrentIndex(0 if combo_index < 0 else combo_index) 

(注:這個工作,你顯然必須確保的第一項在組合框中是一個空白項目)。

+0

我得到的錯誤'#AttributeError的: 'NoneType' 對象有沒有屬性 '文本' #'在該行'ITEM_NAME = STR(item_col.text())','使用也currentText'給我同樣的錯誤...任何想法? – dissidia

+0

@dissidia。這些行在*我的答案引用的代碼段之前。你是否聲稱我提出的改變會以某種方式導致這些錯誤? – ekhumoro

+0

我試圖用我的代碼替換我的for循環,但我得到錯誤..但即使如此,當我用'item_name'省略了行時,我仍然得到'shirt_02'爲紅色的相同輸出 – dissidia