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.pswp.cn/news/906192.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906192.shtml
英文地址,請注明出處:http://en.pswp.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、這六種又分…