你遇到的错误:
```
# Error: TypeError: file <maya console> line 62: Invalid flag 'numberOfColumns'
```
说明你正在使用的 Maya 版本 **不支持 `treeView` 的 `numberOfColumns` 参数**。
---
## 🔍 原因分析:
- `treeView` 控件从 **Maya 2018 开始支持多列功能(`numberOfColumns`)**
- 如果你使用的是 **Maya 2017 或更早版本**,该参数并不存在,因此会报错
- 你希望代码兼容 **Maya 2018 及以上版本**,但当前运行的 Maya 版本可能低于 2018
---
## ✅ 解决方案:自动检测 Maya 版本并使用兼容方式创建表格
我们可以使用 `maya.mel` 或 `maya.cmds.about` 来获取当前 Maya 的版本,并根据版本号决定是否使用 `treeView` 多列模式,或使用 `gridLayout` + `text` 实现一个兼容的表格。
---
## ✅ 完整兼容代码(自动检测 Maya 版本,兼容 2017 及以上)
```python
# -*- coding: utf-8 -*-
from __future__ import print_function, division
import maya.cmds as cmds
import os
# 兼容 Maya 2017 及以下版本的表格实现
try:
import maya.mel as mel
maya_version = int(mel.eval("getApplicationVersionAsFloat"))
except:
maya_version = 2017 # 假设默认为 2017
print("Current Maya Version: {}".format(maya_version))
texture_node_map = {}
selected_texture = None
# 用于兼容的列宽
col1 = 200
col2 = 300
col3 = 150
# Maya 2018+ 使用 treeView
if maya_version >= 2018:
tree_view_ctrl = "textureTreeView"
def update_texture_list():
global texture_node_map, selected_texture
selected_texture = None
texture_node_map.clear()
if cmds.treeView(tree_view_ctrl, exists=True):
cmds.treeView(tree_view_ctrl, edit=True, removeAll=True)
else:
tree_view = cmds.treeView(
tree_view_ctrl,
parent='textureListLayout',
numberOfColumns=3,
columnWidth=[(1, col1), (2, col2), (3, col3)],
columnAlign=[(1, 'left'), (2, 'left'), (3, 'left')],
label=[(1, 'Name'), (2, 'Path'), (3, 'Colorspace')],
selectCommand=lambda item: on_texture_selected(item)
)
textures_with_info = get_texture_nodes_with_color_space_and_name()
for tex, name, path, cs in textures_with_info:
item_id = name + path + cs
cmds.treeView(tree_view_ctrl, edit=True, addItem=(item_id, ""))
cmds.treeView(tree_view_ctrl, edit=True, setColumnLabel=(item_id, 1, name))
cmds.treeView(tree_view_ctrl, edit=True, setColumnLabel=(item_id, 2, path))
cmds.treeView(tree_view_ctrl, edit=True, setColumnLabel=(item_id, 3, cs))
texture_node_map[item_id] = tex
else:
# Maya 2017 及以下使用 gridLayout + text 模拟表格
table_layout = "textureTableLayout"
def update_texture_list():
global texture_node_map
texture_node_map.clear()
if cmds.layout(table_layout, exists=True):
cmds.deleteUI(table_layout)
layout = cmds.gridLayout(table_layout, numberOfRows=1, cellWidthHeight=(10, 20), parent="textureListLayout")
# 表头
cmds.text(label="Name", align="left", parent=layout, width=col1)
cmds.text(label="Path", align="left", parent=layout, width=col2)
cmds.text(label="Colorspace", align="left", parent=layout, width=col3)
textures_with_info = get_texture_nodes_with_color_space_and_name()
for tex, name, path, cs in textures_with_info:
item_id = name + path + cs
cmds.text(label=name, align="left", parent=layout, width=col1, ann=item_id)
cmds.text(label=path, align="left", parent=layout, width=col2, ann=item_id)
cmds.text(label=cs, align="left", parent=layout, width=col3, ann=item_id)
texture_node_map[item_id] = tex
# 点击事件模拟
def on_click_event(ctrl):
item_id = cmds.text(ctrl, query=True, ann=True)
on_texture_selected(item_id)
# 重写 create_custom_color_space_gui 来绑定点击事件
def create_custom_color_space_gui():
window_name = "CustomTextureColorSpaceTool"
if cmds.window(window_name, exists=True):
cmds.deleteUI(window_name)
window = cmds.window(window_name, title="Color Space Tool", widthHeight=(900, 500), resizeToFitChildren=True)
main_layout = cmds.columnLayout(adjustableColumn=True, rowSpacing=10)
# 表格标题
cmds.text(label="Texture List (Name | Path | Color Space):", height=30, align='left')
# 使用 layout 包裹表格
list_layout = cmds.columnLayout('textureListLayout', adjustableColumn=True, parent=main_layout)
# 初始化贴图列表
update_texture_list()
# 如果是低版本 Maya,绑定点击事件
if maya_version < 2018:
children = cmds.layout(table_layout, query=True, childArray=True) or []
for ctrl in children:
if cmds.control(ctrl, exists=True) and cmds.objectTypeUI(ctrl) == "text":
cmds.text(ctrl, edit=True, mouseClickCommand=lambda x, c=ctrl: on_click_event(c))
cmds.setParent('..') # 返回 main_layout
refresh_btn = cmds.button(label="Refresh", command=lambda x: update_texture_list())
# 按钮布局 - 6 个色彩空间按钮横向排列
color_button_layout = cmds.rowLayout("colorButtonLayout", numberOfColumns=6,
adjustableColumn=True,
columnAttach=[(i, 'both', 10) for i in range(1, 7)],
parent=main_layout)
bg_color = [0.3, 0.6, 1.0]
# 创建按钮并命名
cmds.button("colorButton1", label="Raw", backgroundColor=bg_color,
command=lambda x, cs='Raw': on_set_color_space("", cs))
cmds.button("colorButton2", label="Utility - Raw", backgroundColor=bg_color,
command=lambda x, cs='Utility - Raw': on_set_color_space("", cs))
cmds.button("colorButton3", label="sRGB", backgroundColor=bg_color,
command=lambda x, cs='sRGB': on_set_color_space("", cs))
cmds.button("colorButton4", label="ACES - ACEScg", backgroundColor=bg_color,
command=lambda x, cs='ACES - ACEScg': on_set_color_space("", cs))
cmds.button("colorButton5", label="Utility - sRGB - Texture", backgroundColor=bg_color,
command=lambda x, cs='Utility - sRGB - Texture': on_set_color_space("", cs))
cmds.button("colorButton6", label="Utility - Linear - sRGB", backgroundColor=bg_color,
command=lambda x, cs='Utility - Linear - sRGB': on_set_color_space("", cs))
cmds.setParent('..') # 返回 main_layout
# 新增按钮:将贴图路径改为文件名
cmds.button(label="Use File Name Only", command=lambda x: set_texture_path_to_file_name_only())
# 显示窗口
cmds.showWindow(window)
def get_texture_nodes_with_color_space_and_name():
textures = cmds.ls(type='file')
result = []
for tex in textures:
try:
cs = cmds.getAttr(tex + '.colorSpace')
except:
cs = u'未设置'
try:
path = cmds.getAttr(tex + '.fileTextureName')
if path:
full_path = path
tex_name = os.path.basename(path)
else:
full_path = u'未指定'
tex_name = u'未指定'
except:
full_path = u'获取失败'
tex_name = u'获取失败'
result.append((tex, tex_name, full_path, cs))
return result
def on_texture_selected(item):
global selected_texture
selected_texture = texture_node_map.get(item)
print("Selected Texture Node:", selected_texture)
def on_set_color_space(ctrl_name, color_space):
global selected_texture
if not selected_texture:
cmds.confirmDialog(title=u'提示', message=u'请先从列表中选择一个贴图。', button=[u'确定'])
return
try:
cmds.setAttr(selected_texture + '.colorSpace', color_space, type='string')
print(u"已将 {} 设置为 {} 色彩空间。".format(selected_texture, color_space))
cmds.confirmDialog(title=u'完成', message=u'已修改 {} 的色彩空间为 {}。'.format(selected_texture, color_space), button=[u'确定'])
except Exception as e:
cmds.confirmDialog(title=u'错误', message=u'无法设置色彩空间:{}'.format(str(e)), button=[u'确定'])
def set_texture_path_to_file_name_only():
textures = cmds.ls(type='file')
modified_count = 0
for tex in textures:
try:
path = cmds.getAttr(tex + '.fileTextureName')
if path and os.path.exists(path):
filename = os.path.basename(path)
cmds.setAttr(tex + '.fileTextureName', filename, type='string')
print("已将 {} 的路径设置为: {}".format(tex, filename))
modified_count += 1
else:
print("跳过 {}: 路径无效或文件不存在".format(tex))
except Exception as e:
print("无法修改 {}: {}".format(tex, str(e)))
if modified_count > 0:
cmds.confirmDialog(title="完成", message="已修改 {} 个贴图路径为文件名".format(modified_count), button=["确定"])
else:
cmds.confirmDialog(title="提示", message="没有贴图路径被修改", button=["确定"])
# 创建 GUI
create_custom_color_space_gui()
```
---
### ✅ 功能说明:
| Maya 版本 | 控件 | 功能 |
|-----------|------|------|
| 2018+ | `treeView` | 支持列拖动、多列、点击事件 |
| 2017 及以下 | `gridLayout` + `text` | 模拟表格、支持点击、列对齐 |
---
### ✅ 优势:
- ✅ 自动检测 Maya 版本
- ✅ Maya 2018+ 使用 `treeView` 实现完整功能
- ✅ Maya 2017 及以下使用 `gridLayout` 实现兼容表格
- ✅ Python 2 & 3 都兼容(不依赖 `six`)
- ✅ 所有内容左对齐,避免错位
---
###