using UnityEngine; using UnityEditor; using System.IO; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using NPOI.HSSF.UserModel; using TMPro; using System.Collections.Generic; public class ExcelFromHierarchy : EditorWindow { private string folderPath = "Assets/ExcelData"; private string fileName = "data.xlsx"; [MenuItem("Tools/Hierarchy -> Excel 写入(组件限定,InputField停止子物体)")] public static void ShowWindow() { GetWindow("Excel 写入组件限定"); } private void OnGUI() { GUILayout.Label("Hierarchy -> Excel 写入工具", EditorStyles.boldLabel); folderPath = EditorGUILayout.TextField("目标文件夹", folderPath); fileName = EditorGUILayout.TextField("表名(文件名)", fileName); if (GUILayout.Button("写入选中物体数据到 Excel")) { var selected = Selection.activeGameObject; if (selected == null) { Debug.LogWarning("请先在 Hierarchy 中选中一个物体"); return; } string sheetName = selected.name; WriteHierarchyToExcel(folderPath, fileName, selected, sheetName); } } private void WriteHierarchyToExcel(string folderPath, string fileName, GameObject root, string sheetName) { if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath); string filePath = Path.Combine(folderPath, fileName); IWorkbook workbook = null; ISheet sheet = null; if (File.Exists(filePath)) { using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { if (Path.GetExtension(fileName).ToLower() == ".xls") workbook = new HSSFWorkbook(fs); else workbook = new XSSFWorkbook(fs); } } else { if (Path.GetExtension(fileName).ToLower() == ".xls") workbook = new HSSFWorkbook(); else workbook = new XSSFWorkbook(); } sheet = workbook.GetSheet(sheetName) ?? workbook.CreateSheet(sheetName); // 清空 Sheet int lastRow = sheet.LastRowNum; for (int i = lastRow; i >= 0; i--) { var row = sheet.GetRow(i); if (row != null) sheet.RemoveRow(row); } int currentRow = 0; TraverseHierarchy(root.transform, "", (key, value) => { var row = sheet.CreateRow(currentRow++); row.CreateCell(0).SetCellValue(key); row.CreateCell(1).SetCellValue(value); }); using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { workbook.Write(fs); } AssetDatabase.Refresh(); Debug.Log($"Hierarchy -> Excel 写入完成: {fileName} Sheet: {sheetName}"); } /// /// 遍历子物体 /// - 一旦找到 TMP_InputField,只获取 text 并停止对子物体搜索 /// - TMP_Dropdown / TMP_Text 同理 /// - 否则继续递归遍历子物体 /// private void TraverseHierarchy(Transform current, string pathPrefix, System.Action writeAction) { string currentPath = string.IsNullOrEmpty(pathPrefix) ? current.name : pathPrefix + "-" + current.name; // TMP_InputField 优先判断 TMP_InputField tmpInput = current.GetComponent(); if (tmpInput != null) { writeAction?.Invoke(currentPath, tmpInput.text); return; // 找到 InputField,停止搜索子物体 } TMP_Dropdown tmpDropdown = current.GetComponent(); if (tmpDropdown != null) { List opts = new List(); foreach (var o in tmpDropdown.options) opts.Add(o.text); writeAction?.Invoke(currentPath, string.Join("-", opts)); return; // 找到 Dropdown,停止搜索子物体 } TMP_Text tmpText = current.GetComponent(); if (tmpText != null) { writeAction?.Invoke(currentPath, tmpText.text); return; // 找到 Text,停止搜索子物体 } // 当前物体没有组件,递归遍历子物体 foreach (Transform child in current) { TraverseHierarchy(child, currentPath, writeAction); } } }