TreeViewをマルチカラム表示する方法です。
前提
TreeViewの基本的な使い方は下記の記事で説明しています。
本記事は、上の記事の実装を元にしています。
重複する部分は説明を省いていますので、理解しづらい部分などあれば上の記事を参照してください。
実装
まずは実装の全貌を書きます。
using UnityEngine; using UnityEditor.IMGUI.Controls; using UnityEditor; using System.Collections.Generic; public class ExampleTreeElement { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } public ExampleTreeElement Parent { get; private set; } private List<ExampleTreeElement> _children = new List<ExampleTreeElement>(); public List<ExampleTreeElement> Children { get { return _children; } } /// <summary> /// 子を追加する /// </summary> public void AddChild(ExampleTreeElement child) { if (child.Parent != null) { child.Parent.RemoveChild(child); } Children.Add(child); child.Parent = this; } /// <summary> /// 子を削除する /// </summary> public void RemoveChild(ExampleTreeElement child) { if (Children.Contains(child)) { Children.Remove(child); child.Parent = null; } } } class TreeViewExampleWindow : EditorWindow { [SerializeField] private TreeViewState _treeViewState; private ExampleTreeView _treeView; private SearchField _searchField; [MenuItem ("Window/Tree View Example")] private static void Open () { GetWindow<TreeViewExampleWindow> (ObjectNames.NicifyVariableName(typeof(TreeViewExampleWindow).Name)); } private void OnEnable () { if (_treeViewState == null) { _treeViewState = new TreeViewState (); } var nameColumn = new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Name"), headerTextAlignment = TextAlignment.Center, canSort = false, width = 100, minWidth = 50, autoResize = true, allowToggleVisibility = false }; var descriptionColumn = new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Description"), headerTextAlignment = TextAlignment.Center, canSort = false, width = 150, minWidth = 50, autoResize = true, allowToggleVisibility = false }; var headerState = new MultiColumnHeaderState(new MultiColumnHeaderState.Column[]{ nameColumn, descriptionColumn }); var multiColumnHeader = new MultiColumnHeader(headerState); // カラムヘッダーとともにTreeViewを作成 _treeView = new ExampleTreeView(_treeViewState, multiColumnHeader); // モデルを作成 var currentId = 0; var root = new ExampleTreeElement { Id = ++currentId, Name = "1" }; for (int i = 0; i < 2; i++) { var element = new ExampleTreeElement { Id = ++currentId, Name = "1-" + (i + 1) }; for (int j = 0; j < 2; j++) { element.AddChild(new ExampleTreeElement { Id = ++currentId, Name = "1-" + (i + 1) + "-" + (j + 1) }); } root.AddChild(element); } // TreeViewを初期化 _treeView.Setup(new List<ExampleTreeElement>{root}.ToArray()); // SearchFieldを初期化 _searchField = new SearchField(); _searchField.downOrUpArrowKeyPressed += _treeView.SetFocusAndEnsureSelectedItem; } private void OnGUI () { // 検索窓を描画 using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar)) { GUILayout.Space (100); GUILayout.FlexibleSpace(); _treeView.searchString = _searchField.OnToolbarGUI (_treeView.searchString); } // TreeViewを描画 var rect = EditorGUILayout.GetControlRect(false, 200); _treeView.OnGUI(rect); } } public class ExampleTreeView : TreeView { class ExampleTreeViewItem : TreeViewItem { public ExampleTreeElement Data { get; set; } } private ExampleTreeElement[] _baseElements; // 初期化時にMultiColumnHeaderを渡す public ExampleTreeView(TreeViewState treeViewState, MultiColumnHeader multiColumnHeader) : base(treeViewState, multiColumnHeader) { } public void Setup(ExampleTreeElement[] baseElements) { _baseElements = baseElements; Reload(); } protected override TreeViewItem BuildRoot () { return new TreeViewItem { id = 0, depth = -1, displayName = "Root" }; } protected override IList<TreeViewItem> BuildRows(TreeViewItem root) { var rows = GetRows() ?? new List<TreeViewItem>(); rows.Clear (); foreach (var baseElement in _baseElements) { var baseItem = CreateTreeViewItem(baseElement); root.AddChild (baseItem); rows.Add (baseItem); if (baseElement.Children.Count >= 1) { if (IsExpanded (baseItem.id)) { AddChildrenRecursive(baseElement, baseItem, rows); } else { baseItem.children = CreateChildListForCollapsedParent(); } } } SetupDepthsFromParentsAndChildren(root); return rows; } private void AddChildrenRecursive (ExampleTreeElement element, TreeViewItem item, IList<TreeViewItem> rows) { foreach (var childElement in element.Children) { var childItem = CreateTreeViewItem(childElement); item.AddChild (childItem); rows.Add (childItem); if (childElement.Children.Count >= 1) { if (IsExpanded (childElement.Id)) { AddChildrenRecursive(childElement, childItem, rows); } else { childItem.children = CreateChildListForCollapsedParent(); } } } } private ExampleTreeViewItem CreateTreeViewItem(ExampleTreeElement model) { return new ExampleTreeViewItem { id = model.Id, displayName = model.Name, Data = model }; } protected override void RowGUI (RowGUIArgs args) { var item = (ExampleTreeViewItem)args.item; // 表示されているカラム毎に処理 for (int i = 0; i < args.GetNumVisibleColumns (); ++i) { // いまのセルのRect var cellRect = args.GetCellRect(i); var columnIndex = args.GetColumn(i); // セルのRectを上下センタリングするユーティリティメソッド(不要なら使わなくていい) CenterRectUsingSingleLineHeight(ref cellRect); if (columnIndex == 0) { // デフォルトのセル描画 base.RowGUI(args); } else if (columnIndex == 1) { // テキストフィールド(モデルを書き換える) item.Data.Description = GUI.TextField(cellRect, item.Data.Description); } } } }
クラス構成は前の記事のものと変わっていません。
変更点としては、まずExampleTreeView
クラスの中でExampleTreeViewItem
を定義しています。
これはTreeViewItem
にモデルを持たせただけのものです。
またExampleTreeView
のコンストラクタではMultiColumnHeader
を渡しています。
これはカラムのヘッダ部分を定義するもので、TreeViewExampleWindow
のOnEnable
あたりで作成しています。
これらを実装したうえで、RowGUI
を上記のようにカラムに対応した形で実装することで、
複数カラムが実現できます。
結果
Windowを表示すると次のようになります。
関連
参考
↑からDLできるTreeViewExamples.zip
がとても参考になります