Unity editor文件数UI(支持勾选框)

unity editor文件数(支持勾选框)

使用的时候new一个box即可

using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[Serializable]
public class TGFileTreeViewBox<T> where T : OdinMenuEditorWindow
{public TGFileTreeView fileTreeView;private Vector2 scrollPosition;public TGFileTreeViewBox(bool ShowCheckboxes = true){fileTreeView = new TGFileTreeView(new List<string>(), ThisRepaint);fileTreeView.ShowCheckboxes = ShowCheckboxes;//fileTreeView = new TGFileTreeView(GetFilePathsTest(), ThisRepaint);fileTreeView.SelectAll();}public TGFileTreeViewBox(List<string> paths, bool ShowCheckboxes = true){//for (int i = 0; i < paths.Count; i++)//{//    Logger.Log($"文件夹树视图:{paths[i]}");//}fileTreeView = new TGFileTreeView(paths, ThisRepaint);fileTreeView.ShowCheckboxes = ShowCheckboxes;//fileTreeView = new TGFileTreeView(GetFilePathsTest(), ThisRepaint);//fileTreeView.ToggleExpandAll(true);fileTreeView.SelectAll();}[OnInspectorGUI]private void DrawCustomInspector(){float contentHeight = fileTreeView.GetHeight();float maxHeight = Mathf.Min(contentHeight, 250f);scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Height(maxHeight));fileTreeView.DrawTreeView();//if (GUILayout.Button("打印选中路径"))//{//    foreach (var path in fileTreeView.CheckedPaths)//    {//        Logger.Log($"选中了--{path}");//    }//}//if (GUILayout.Button("打印未选中路径"))//{//    foreach (var path in fileTreeView.UncheckedPaths)//    {//        Logger.Log($"未选中--{path}");//    }//}//if (GUILayout.Button("打印选中文件路径"))//{//    foreach (var path in fileTreeView.CheckedFilePaths)//    {//        Logger.Log($"选中文件了--{path}");//    }//}GUILayout.EndScrollView();}// 刷新界面的方法public static void ThisRepaint(){var window = UnityEditor.EditorWindow.GetWindow<T>();window?.Repaint();}private static List<string> GetFilePathsTest(){// 直接定义路径数据return new List<string>{"Assets/_Test/sedan.prefab","Assets/_Test/mat/New Material.mat","Assets/_Test/mat/New Material 1.mat","Assets/_Test/mat/New Material 2.mat","Assets/_Test/mat/New Material 3.mat","Assets/_Test/New Material 1.mat","Assets/_Test/New Material 2.mat","Assets/_Test/New Material 3.mat","Assets/_Test/New Material 4.mat","Assets/_Test/New Material.mat","Assets/_Test/source/sedan.fbx","Assets/_Test/source/sedan 1.fbx","Assets/_Test/TestNull","Assets/_Test/textures/internal_ground_ao_texture.jpeg","Assets/_Test/textures/internal_ground_ao_texture 1.jpeg","Assets/_Test/textures/internal_ground_ao_texture 2.jpeg","Assets/_Test/textures/internal_ground_ao_texture 3.jpeg","Assets/_Test/textures/internal_ground_ao_texture 4.jpeg","Assets/_Test/textures/internal_ground_ao_texture 5.jpeg","Assets/_Test/textures/internal_ground_ao_texture 6.jpeg","Assets/_Test/textures/internal_ground_ao_texture 7.jpeg","Assets/_Test/textures/internal_ground_ao_texture 8.jpeg","Assets/_Test/textures/internal_ground_ao_texture 9.jpeg","Assets/_Test/textures/internal_ground_ao_texture 10.jpeg","Assets/_Test/textures/internal_ground_ao_texture.tga"};}
}
using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;public class TGFileTreeView
{private List<string> allfilePaths = new List<string>(); // 传入的路径private List<string> filePaths = new List<string>(); // 当前有效路径,经过过滤private List<string> checkedPaths = new List<string>(); // 勾选的路径private List<string> uncheckedPaths = new List<string>(); // 未勾选的路径private List<string> checkedFilePaths = new List<string>(); // 选中的文件路径列表private Dictionary<string, bool> foldoutStates = new Dictionary<string, bool>();private Dictionary<string, bool> checkboxStates = new Dictionary<string, bool>();private string selectedFilePath = "";private Action repaintAction;private int treeHeight;private bool isExpandAll = true;public List<string> CheckedPaths => checkedPaths;public List<string> UncheckedPaths => uncheckedPaths;public List<string> AllPaths => allfilePaths; // 传入的路径列表public List<string> CurrentValidPaths => filePaths; // 当前有效路径public List<string> CheckedFilePaths //选中的文件路径列表{get{checkedFilePaths.Clear();foreach (var item in checkedPaths){if (Path.HasExtension(item)){checkedFilePaths.Add(item);}}return checkedFilePaths;}}public Action<string, bool> OnCheckStateChanged; // path 和状态public bool ShowCheckboxes = true; // 全局控制是否显示勾选框public TGFileTreeView(List<string> paths, System.Action repaintAction){allfilePaths = paths;this.repaintAction = repaintAction;InitializePaths();}// 初始化时计算有效路径,并根据勾选状态更新 CheckedPaths 和 UncheckedPathsprivate void InitializePaths(){// 过滤出有效路径filePaths = allfilePaths.Where(path => File.Exists(path) || Directory.Exists(path)).ToList();// 初始化勾选与取消勾选的路径checkedPaths = new List<string>();uncheckedPaths = new List<string>();foreach (var path in filePaths){checkboxStates[path] = false;uncheckedPaths.Add(path);}}public void DrawTreeView(){CheckForDeletedFiles();if (filePaths.Count == 0){EditorGUILayout.LabelField("没有可用的文件路径!!");return;}DrawFileTree(filePaths);}private void CheckForDeletedFiles(){filePaths.Clear();foreach (var path in allfilePaths){if (File.Exists(path) || Directory.Exists(path)){filePaths.Add(path);}}}private void DrawFileTree(List<string> paths){TGTreeNode root = BuildTree(paths);treeHeight = GetTotalHeight(root);DrawNode(root, 0);}private void DrawNode(TGTreeNode node, int indentLevel){EditorGUILayout.BeginHorizontal();if (!foldoutStates.ContainsKey(node.Path))foldoutStates[node.Path] = isExpandAll;if (!checkboxStates.ContainsKey(node.Path)){checkboxStates[node.Path] = false;UpdateCheckboxLists(node.Path, false);}float lineHeight = 20f;float indentX = indentLevel * 20f;float foldoutWidth = 14f;float spacingA = 20f; // 箭头和勾选框之间float toggleWidth = 18f;float spacingB = 4f; // 勾选框和图标之间float iconWidth = 20f;float spacingC = 4f; // 图标和文件名之间Rect lineRect = GUILayoutUtility.GetRect(0, lineHeight, GUILayout.ExpandWidth(true));float x = lineRect.x + indentX;// 折叠箭头if (node.IsFolder && node.Children.Count > 0){Rect foldoutRect = new Rect(x, lineRect.y + 3, foldoutWidth, 14f);foldoutStates[node.Path] = EditorGUI.Foldout(foldoutRect, foldoutStates[node.Path], GUIContent.none, false);x += foldoutWidth + spacingA;}else{x += foldoutWidth + spacingA;}// 勾选框if (ShowCheckboxes){// 勾选框Rect toggleRect = new Rect(x, lineRect.y + 1, toggleWidth, 18f);bool oldChecked = checkboxStates[node.Path];bool newChecked = GUI.Toggle(toggleRect, oldChecked, GUIContent.none);if (oldChecked != newChecked){checkboxStates[node.Path] = newChecked;UpdateCheckboxLists(node.Path, newChecked);}x += toggleWidth + spacingB;}else{x += spacingB; // 保留缩进对齐}// 图标Texture icon = GetIconForPath(node.Path, node.IsFolder);if (icon != null){Rect iconRect = new Rect(x, lineRect.y, iconWidth, 20f);GUI.DrawTexture(iconRect, icon);x += iconWidth + spacingC;}// 文件名Rect labelRect = new Rect(x, lineRect.y, lineRect.width - (x - lineRect.x), lineHeight);GUIContent labelContent = new GUIContent(GetFileName(node.Path));if (selectedFilePath == node.Path)EditorGUI.DrawRect(lineRect, new Color(0.24f, 0.49f, 0.90f, 0.3f));HandleClick(labelRect, node.Path);GUI.Label(labelRect, labelContent);EditorGUILayout.EndHorizontal();if (node.IsFolder && foldoutStates[node.Path]){foreach (var child in node.Children){DrawNode(child, indentLevel + 1);}}}private void UpdateCheckboxLists(string path, bool isChecked){checkboxStates[path] = isChecked;if (isChecked){if (!checkedPaths.Contains(path)) checkedPaths.Add(path);uncheckedPaths.Remove(path);}else{if (!uncheckedPaths.Contains(path)) uncheckedPaths.Add(path);checkedPaths.Remove(path);}// 更新子项状态var keys = checkboxStates.Keys.ToList();foreach (var kvp in keys){if (kvp != path && kvp.StartsWith(path + "/")){checkboxStates[kvp] = isChecked;if (isChecked){if (!checkedPaths.Contains(kvp)) checkedPaths.Add(kvp);uncheckedPaths.Remove(kvp);}else{if (!uncheckedPaths.Contains(kvp)) uncheckedPaths.Add(kvp);checkedPaths.Remove(kvp);}}}OnCheckStateChanged?.Invoke(path, isChecked);UpdateParentCheckboxStates(path);}private void UpdateParentCheckboxStates(string path){string parentPath = GetParentPath(path);if (string.IsNullOrEmpty(parentPath)) return;var childPaths = checkboxStates.Keys.Where(k => GetParentPath(k) == parentPath).ToList();bool anyChildChecked = childPaths.Any(k => checkboxStates.ContainsKey(k) && checkboxStates[k]);checkboxStates[parentPath] = anyChildChecked;if (anyChildChecked){if (!checkedPaths.Contains(parentPath)) checkedPaths.Add(parentPath);uncheckedPaths.Remove(parentPath);}else{if (!uncheckedPaths.Contains(parentPath)) uncheckedPaths.Add(parentPath);checkedPaths.Remove(parentPath);}UpdateParentCheckboxStates(parentPath);}private string GetParentPath(string path){if (string.IsNullOrEmpty(path)) return null;int lastSlashIndex = path.LastIndexOf('/');if (lastSlashIndex <= 0) return null;return path.Substring(0, lastSlashIndex);}private void HandleClick(Rect rect, string path){Event e = Event.current;if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)){if (e.clickCount == 1){selectedFilePath = path;repaintAction?.Invoke();}else if (e.clickCount == 2){if (File.Exists(path) || Directory.Exists(path)){EditorUtility.FocusProjectWindow();UnityEngine.Object asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);if (asset != null){EditorGUIUtility.PingObject(asset);Selection.activeObject = asset;}}}e.Use();}}private TGTreeNode BuildTree(List<string> paths){TGTreeNode root = new TGTreeNode("Assets", true);foreach (string path in paths){string[] parts = path.Split('/');TGTreeNode current = root;for (int i = 1; i < parts.Length; i++){string part = parts[i];string fullPath = string.Join("/", parts, 0, i + 1);bool isFile = (i == parts.Length - 1) && Path.HasExtension(part);if (!current.HasChild(part)){current.Children.Add(new TGTreeNode(fullPath, !isFile));}current = current.GetChild(part);}}return root;}private string GetFileName(string path){return Path.GetFileName(path);}private int GetTotalHeight(TGTreeNode node){int totalHeight = 25;bool isFolded = !foldoutStates.ContainsKey(node.Path) || !foldoutStates[node.Path];if (node.IsFolder && !isFolded){foreach (var child in node.Children){totalHeight += GetTotalHeight(child);}}return totalHeight;}public int GetHeight(){return treeHeight;}public void ToggleExpandAll(bool _isExpandAll){isExpandAll = _isExpandAll;foldoutStates.Clear();repaintAction?.Invoke();}// 全选public void SelectAll(){foreach (var path in filePaths){if (!checkboxStates.ContainsKey(path)) continue;if (!checkboxStates[path]) // 只有未勾选的才修改{checkboxStates[path] = true;UpdateCheckboxLists(path, true);}}repaintAction?.Invoke(); // 更新界面}// 全不选public void DeselectAll(){foreach (var path in filePaths){if (!checkboxStates.ContainsKey(path)) continue;if (checkboxStates[path]) // 只有勾选的才修改{checkboxStates[path] = false;UpdateCheckboxLists(path, false);}}repaintAction?.Invoke(); // 更新界面}private Texture GetIconForPath(string path, bool isFolder){if (isFolder) return EditorGUIUtility.IconContent("Folder Icon").image;string extension = Path.GetExtension(path).ToLower();switch (extension){case ".prefab": return EditorGUIUtility.IconContent("Prefab Icon").image;case ".fbx":case ".obj":case ".blend": return EditorGUIUtility.IconContent("Mesh Icon").image;case ".mat": return EditorGUIUtility.IconContent("Material Icon").image;case ".shader":case ".compute": return EditorGUIUtility.IconContent("Shader Icon").image;case ".png":case ".jpg": return EditorGUIUtility.IconContent("Texture Icon").image;case ".anim": return EditorGUIUtility.IconContent("Animation Icon").image;case ".controller": return EditorGUIUtility.IconContent("AnimatorController Icon").image;case ".unity": return EditorGUIUtility.IconContent("SceneAsset Icon").image;case ".ttf":case ".otf": return EditorGUIUtility.IconContent("Font Icon").image;default: return EditorGUIUtility.IconContent("DefaultAsset Icon").image;}}
}public class TGTreeNode
{public string Path { get; private set; }public bool IsFolder { get; private set; }public List<TGTreeNode> Children { get; private set; }public TGTreeNode(string path, bool isFolder){Path = path;IsFolder = isFolder;Children = new List<TGTreeNode>();}public bool HasChild(string path){return Children.Exists(child => child.Path.EndsWith(path));}public TGTreeNode GetChild(string path){return Children.Find(child => child.Path.EndsWith(path));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/906192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ通信模式(Simplest)Python示例

RabbitMQ通信模式-Python示例 0.RabbitMQ官网通信模式1.Simplest(简单)模式1.1 发送端1.2 接收端 0.RabbitMQ官网通信模式 1.Simplest(简单)模式 1.1 发送端 # -*- coding: utf-8 -*- """ Author: xxx date: 2025/5/19 11:30 Description: Simaple简单模…

隨筆20250519 Async+ThreadPoolTaskExecutor⾃定义线程池进阶实战

1.ThreadPoolTaskExecutor线程池 有哪⼏个重要参数&#xff0c; 什么时候会创建线程 1.核心綫程數 查看核心綫程數目是否已經滿&#xff0c;未滿 創建一條綫程 執行任務&#xff0c;已滿負責執行第二部 2.阻塞隊列 查看阻塞隊列是否已經滿&#xff0c;未滿將任務加入阻塞隊列&…

YOLO11解决方案之实例分割与跟踪探索

概述 Ultralytics提供了一系列的解决方案,利用YOLO11解决现实世界的问题,包括物体计数、模糊处理、热力图、安防系统、速度估计、物体追踪等多个方面的应用。 实例分割是一项计算机视觉任务,涉及在像素级别识别和勾勒图像中的单个对象。与只按类别对像素进行分类的语义分割…

VScode各文件转化为PDF的方法

文章目录 代码.py文件.ipynb文本和代码夹杂的文件方法 1:使用 VS Code 插件(推荐)步骤 1:安装必要插件步骤 2:安装 `nbconvert`步骤 3:间接导出(HTML → PDF)本文遇见了系列错误:解决方案:问题原因步骤 1:降级 Jinja2 至兼容版本步骤 2:确保 nbconvert 版本兼容替代…

现代计算机图形学Games101入门笔记(十五)

蒙特卡洛积分 为什么用蒙特卡洛积分&#xff0c;用来做什么&#xff1f;跟黎曼积分区别&#xff0c;黎曼积分是平均分成n等分&#xff0c;取每个小块中间的值取计算每个小块面积&#xff0c;再将n份集合加起来。蒙特卡洛积分就是随机取样&#xff0c;假设随机取样点xi,对应的f…

软件架构之-论高并发下的可用性技术

论高并发下的可用性技术 摘要正文摘要 ;2023年2月,本人所在集团公司承接了长三角地区某省渔船图纸电子化审查系统项目开发,该项目旨在为长三角地区渔船建造设计院、以及渔船审图机构提供一个便捷化的服务平台。在此项目中,我作为项目组成员参与了项目建设工作,并担任系统架…

Q-learning 算法学习

Q-learning是一种经典的无模型、基于价值的算法&#xff0c;它通过迭代更新状态-动作对的Q值&#xff0c;最终找到最优策略。 一 Q-learning的核心思想 1.1目标 学习一个状态-动作价值函数 &#xff0c;表示在状态 s 下执行动作 a 并遵循最优策略后的最大累积奖励。 的核心…

鸿蒙生态崛起:开发者机遇与挑战并存

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《热点时事》 期待您的关注 目录 引言 一、何为鸿蒙生态&#xff1f; 二、在鸿蒙生态下开发时遇到的挑战 三、对于鸿蒙生态未…

TCP/IP-——C++编程详解

1. TCP/IP 编程基本概念 TCP&#xff08;传输控制协议&#xff09;&#xff1a;面向连接、可靠的传输层协议&#xff0c;保证数据顺序和完整性。IP&#xff08;网际协议&#xff09;&#xff1a;负责将数据包路由到目标地址。Socket&#xff08;套接字&#xff09;&#xff1a…

Python图像处理基础(三)

Python图像处理基础(三) 文章目录 Python图像处理基础(三)2、计算机色彩(Computer Color)2.5 色彩分辨率2.6 灰度颜色模型2.7 CMYK 颜色模型2.7.1 K 部分2.8 HSL/HSB 颜色模型2、计算机色彩(Computer Color) 2.5 色彩分辨率 人眼可以看到许多不同的颜色,但我们的感知…

Vue路由深度解析:Vue Router与导航守卫

Vue路由深度解析&#xff1a;Vue Router与导航守卫 一、Vue Router基础与安装配置 1. Vue Router核心概念 Vue Router是Vue.js官方的路由管理器&#xff0c;主要功能包括&#xff1a; 嵌套路由映射模块化的路由配置路由参数、查询、通配符细粒度的导航控制自动激活的CSS类链…

前后端分离微服务架构

前后端分离微服务架构 介绍: 前端通过Vue和ElementUI构建界面&#xff0c;使用axios调用后端API。Nginx作为反向代理&#xff0c;将请求路由到Zuul网关。Zuul进行权限验证&#xff08;JWT&#xff09;后&#xff0c;将请求分发到微服务。(身份验证,安全防护(sql注入,xxs跨网站…

iOS 工厂模式

iOS 工厂模式 文章目录 iOS 工厂模式前言工厂模式简单工厂案例场景分析苹果类优点缺点 小结 工厂模式客户端调用**优点****缺点** 抽象工厂模式三个模式对比 前言 笔者之前学习了有关于设计模式的六大原则,之前简单了解过这个工厂模式,今天主要是重新学习一下这个模式,正式系统…

【机器学习】工具入门:飞牛启动Dify Ollama Deepseek

很久没有更新文章了,最近正好需要研究一些机器学习的东西&#xff0c;打算研究一下 difyOllama 以下是基于FN 的dify本地化部署&#xff0c;当然这也可能是全网唯一的飞牛部署dify手册 部署 官方手册&#xff1a;https://docs.dify.ai/en/getting-started/install-self-hos…

安卓A15系统实现修改锁屏界面默认壁纸功能

最近遇到一个A15系统项目&#xff0c;客户要求修改锁屏界面的默认壁纸&#xff0c;客户提供了一张壁纸图片&#xff0c;但是从A15系统的源代码查看时才知道谷歌已经去掉了相关的代码&#xff0c;已经不支持了&#xff0c;A13和A14系统好像是支持的&#xff0c;A15系统的Wallpap…

从理论到实战:模糊逻辑算法的深度解析与应用实践

从理论到实战&#xff1a;模糊逻辑算法的深度解析与应用实践 一、模糊逻辑的核心概念与数学基础 模糊逻辑&#xff08;Fuzzy Logic&#xff09;是一种处理不确定性的数学工具&#xff0c;其核心思想是将传统布尔逻辑的“非黑即白”扩展为连续的隶属度函数。例如&#xff0c;在…

正向代理与反向代理区别及应用

正向代理和反向代理是两种常见的代理服务器类型&#xff0c;它们在网络架构中扮演不同角色&#xff0c;核心区别在于代理对象和使用场景。 1. 正向代理&#xff08;Forward Proxy&#xff09; 定义&#xff1a;正向代理是客户端&#xff08;如浏览器&#xff09;主动配置的代理…

OpenCV CUDA模块中逐元素操作------逻辑运算

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 比较、AND、OR、NOT等。这类操作可用于创建基于条件的掩码&#xff0c;这对于图像分割或特征选择非常有用。 主要函数 1. 按位与 (cv::cuda::b…

一台入网的电脑有6要素, 机器名,mac,ip,俺码,网关,dns,分别有什么作用

一台入网的电脑需要配置的 六大网络要素&#xff08;机器名、MAC地址、IP地址、子网掩码、网关、DNS&#xff09;各自承担不同的关键作用&#xff0c;共同确保设备能正确通信和访问网络资源。以下是它们的详细功能解析&#xff1a; 1. 机器名&#xff08;主机名&#xff09; 作…

MySQL之储存引擎和视图

一、储存引擎 基本介绍&#xff1a; 1、MySQL的表类型由储存引擎(Storage Engines)决定&#xff0c;主要包括MyISAM、innoDB、Memory等。 2、MySQL数据表主要支持六种类型&#xff0c;分别是&#xff1a;CSV、Memory、ARCHIVE、MRG_MYISAN、MYISAM、InnoBDB。 3、这六种又分…