Мои Уведомления
Привет, !
Мой Аккаунт Мои Финансы Мои Подписки Мои Настройки Выход
Руководство API скрипты

Информация на этой странице предполагает, что читатель имеет базовые знания концепций IMGUI (Immediate Mode GUI). Для получения информации о IMGUI и настройке окон редактора см. Расширение редактора и Блог IMGUI Unity.

TreeView — это элемент управления IMGUI, используемый для отображения иерархических данных, которые можно разворачивать и сворачивать. Используйте TreeView для создания настраиваемых списков и таблиц с несколькими столбцами для окон редактора, которые вы можете использовать вместе с другими элементами управления и компонентами IMGUI.

См. документацию Unity Scripting API в TreeView для получения информации о доступных функциях TreeView API.

Пример TreeView с MultiColumnHeader и SearchField.
Пример TreeView с MultiColumnHeader и SearchField.

Обратите внимание, что TreeView не является моделью данных в виде дерева. Вы можете построить TreeView, используя любую предпочтительную древовидную структуру данных. Это может быть древовидная модель C# или древовидная структура на основе Unity, например иерархия Transform.

рендерингпроцесс вывода графики на экран (или текстуры рендеринга). По умолчанию основная камера в Unity отображает изображение на экране. Подробнее
См. в Словарь
TreeView обрабатывается путем определения списка развернутых элементов, называемых ряды. Каждая строка представляет один TreeViewItem. Каждый TreeViewItem содержит информацию о родителях и дочерних элементах, которая используется TreeView для управления навигацией (ввод клавиш и мыши).

TreeView имеет один корневой элемент TreeViewItem, который скрыт и не отображается в редакторе. Этот элемент является корневым для всех остальных элементов.

Важные классы и методы

Наиболее важными классами помимо самого TreeView являются TreeViewItem и TreeViewState.

TreeViewState (TreeViewState) содержит информацию о состоянии, которая изменяется при взаимодействии с TreeView. поля в редакторе, такие как состояние выбора, развернутое состояние, состояние навигации и состояние прокрутки. TreeViewState — это единственное состояние, которое можно сериализовать. Сам TreeView не является сериализуемым — он реконструируется из данных, которые он представляет, когда он создается или перезагружается. Добавьте TreeViewState в качестве поля в класс, производный от EditorWindow, чтобы гарантировать, что измененные пользователем состояния не будут потеряны при перезагрузке скриптыЧасть кода, позволяющая создавать собственные компоненты, запускать игровые события, изменять свойства компонентов с течением времени и реагировать на действия пользователя в как вам угодно. Подробнее
Посмотреть в Словарь
или войти в режим воспроизведения (см. документацию по расширение редактора для получения информации о том, как это сделать). Пример класса, содержащего поле TreeViewState, см. в разделе Пример 1. Простой TreeView , ниже.

TreeViewItem (TreeViewItem) содержит данные об отдельном элементе TreeView и используется для построения представления древовидной структуры в Редакторе. Каждый TreeViewItem должен иметь уникальный целочисленный идентификатор (уникальный среди всех элементов в TreeView). Идентификатор используется для поиска элементов в дереве для состояния выбора, расширенного состояния и навигации. Если дерево представляет объекты Unity, используйте GetInstanceID для каждого объекта в качестве идентификатора для TreeViewItem. Идентификаторы используются в TreeViewState для сохранения измененных пользователем состояний (например, развернутых элементов) при перезагрузке скриптов или входе в режим воспроизведения в редакторе.

Все TreeViewItems имеют свойство depth, которое указывает визуальный отступ. Дополнительную информацию см. в приведенном ниже примере Инициализация TreeView.

BuildRoot (BuildRoot) – это единственный абстрактный метод TreeView, который должен быть реализован для создания TreeView. Используйте этот метод для обработки создания корневого элемента дерева. Это вызывается каждый раз, когда для дерева вызывается Reload. Для простых деревьев, использующих небольшие наборы данных, создайте все дерево TreeViewItems под корневым элементом в BuildRoot. Для очень больших деревьев не оптимально создавать все дерево при каждой перезагрузке. В этом случае создайте корень, а затем переопределите метод BuildRows, чтобы создавать элементы только для текущих строк. Пример использования BuildRoot см. в разделе Пример 1: простой TreeView ниже.

BuildRows (BuildRows) – это виртуальный метод, в котором реализация по умолчанию обрабатывает построение списка строк. на основе полного дерева, созданного в BuildRoot. Если в BuildRoot был создан только корень, этот метод следует переопределить для обработки развернутых строк. Дополнительную информацию см. в разделе Инициализация TreeView ниже.

На этой диаграмме показаны порядок и повторение методов событий BuildRoot и BuildRows в течение жизненного цикла TreeView. Обратите внимание, что метод BuildRoot вызывается один раз при каждом вызове Reload. BuildRows вызывается чаще, потому что он вызывается один раз при Reload (сразу после BuildRoot) и каждый раз, когда TreeViewItem разворачивается или сворачивается.

Инициализация TreeView

TreeView инициализируется при вызове метода Reload из объекта TreeView.

Есть два способа настроить TreeView:

  1. Создать полное дерево. Создайте TreeViewItem для всех элементов данных модели дерева. Это значение по умолчанию и требует меньше кода для настройки. Полное дерево строится, когда BuildRoot вызывается из объекта TreeView.

  2. Создавать только развернутые элементы. Этот подход требует переопределения BuildRows для ручного управления отображаемыми строками и BuildRoot используется только для создания корневого TreeViewItem. Этот подход лучше всего масштабируется с большими наборами данных или данными, которые часто меняются.

Используйте первый подход для небольших наборов данных или для данных, которые не часто меняются. Используйте второй подход для больших наборов данных или данных, которые часто изменяются, потому что быстрее создавать только расширенные элементы, а не полное дерево.

Есть три способа настроить TreeViewItems:

  • Создайте TreeViewItem с инициализированными с самого начала дочерними элементами, родителем и глубинами.

  • Создайте TreeViewItem с родительским и дочерним элементами, а затем используйте SetupDepthsFromParentsAndChildren для установки глубины.

  • Создайте объекты TreeViewItem только с информацией о глубине, а затем используйте SetupDepthsFromParentsAndChildren для установки родительской и дочерней ссылок.

Примеры

Чтобы просмотреть проект и исходный код приведенных ниже примеров, загрузите TreeViewExamples.zip.

Пример 1. Простой TreeView

Чтобы создать TreeView, создайте класс, расширяющий класс TreeView, и реализуйте абстрактный метод BuildRoot. В следующем примере создается простой TreeView.

class SimpleTreeView : TreeView { public SimpleTreeView(TreeViewState treeViewState) : base(treeViewState) { Reload(); } protected override TreeViewItem BuildRoot () { // BuildRoot is called every time Reload is called to ensure that TreeViewItems // are created from data. Here we create a fixed set of items. In a real world example, // a data model should be passed into the TreeView and the items created from the model. // This section illustrates that IDs should be unique. The root item is required to // have a depth of -1, and the rest of the items increment from that. var root = new TreeViewItem {id = 0, depth = -1, displayName = "Root"}; var allItems = new List { new TreeViewItem {id = 1, depth = 0, displayName = "Animals"}, new TreeViewItem {id = 2, depth = 1, displayName = "Mammals"}, new TreeViewItem {id = 3, depth = 2, displayName = "Tiger"}, new TreeViewItem {id = 4, depth = 2, displayName = "Elephant"}, new TreeViewItem {id = 5, depth = 2, displayName = "Okapi"}, new TreeViewItem {id = 6, depth = 2, displayName = "Armadillo"}, new TreeViewItem {id = 7, depth = 1, displayName = "Reptiles"}, new TreeViewItem {id = 8, depth = 2, displayName = "Crocodile"}, new TreeViewItem {id = 9, depth = 2, displayName = "Lizard"}, }; // Utility method that initializes the TreeViewItem.children and .parent for all items. SetupParentsAndChildrenFromDepths (root, allItems); // Return root of the tree return root; } }

В этом примере информация о глубине используется для построения TreeView. Наконец, вызов SetupDepthsFromParentsAndChildren устанавливает родительские и дочерние данные элементов TreeViewItem.

Обратите внимание, что существует два способа настройки TreeViewItem: установить родительский и дочерний элементы напрямую или использовать AddChild. метод, как показано в следующем примере:

protected override TreeViewItem BuildRoot() { var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" }; var animals = new TreeViewItem { id = 1, displayName = "Animals" }; var mammals = new TreeViewItem { id = 2, displayName = "Mammals" }; var tiger = new TreeViewItem { id = 3, displayName = "Tiger" }; var elephant = new TreeViewItem { id = 4, displayName = "Elephant" }; var okapi = new TreeViewItem { id = 5, displayName = "Okapi" }; var armadillo = new TreeViewItem { id = 6, displayName = "Armadillo" }; var reptiles = new TreeViewItem { id = 7, displayName = "Reptiles" }; var croco = new TreeViewItem { id = 8, displayName = "Crocodile" }; var lizard = new TreeViewItem { id = 9, displayName = "Lizard" }; root.AddChild(animals); animals.AddChild(mammals); animals.AddChild(reptiles); mammals.AddChild(tiger); mammals.AddChild(elephant); mammals.AddChild(okapi); mammals.AddChild(armadillo); reptiles.AddChild(croco); reptiles.AddChild(lizard); SetupDepthsFromParentsAndChildren(root); return root; }

Альтернативный метод BuildRoot для класса SimpleTreeView выше

В следующем примере показано EditorWindow, содержащее SimpleTreeView. TreeView создаются с помощью экземпляра TreeViewState. Разработчик TreeView должен определить, как следует обрабатывать это состояние представления: должно ли его состояние сохраняться до следующего сеанса Unity или оно должно сохранять свое состояние только после перезагрузки скриптов (либо при входе в режим Play, либо при перекомпиляции скриптов). В этом примере TreeViewState сериализуется в EditorWindow, гарантируя, что TreeView сохраняет свое состояние при закрытии и повторном открытии редактора.

using System.Collections.Generic; using UnityEngine; using UnityEditor.IMGUI.Controls; class SimpleTreeViewWindow : EditorWindow { // SerializeField is used to ensure the view state is written to the window // layout file. This means that the state survives restarting Unity as long as the window // is not closed. If the attribute is omitted then the state is still serialized/deserialized. [SerializeField] TreeViewState m_TreeViewState; //The TreeView is not serializable, so it should be reconstructed from the tree data. SimpleTreeView m_SimpleTreeView; void OnEnable () { // Check whether there is already a serialized view state (state // that survived assembly reloading) if (m_TreeViewState == null) m_TreeViewState = new TreeViewState (); m_SimpleTreeView = new SimpleTreeView(m_TreeViewState); } void OnGUI () { m_SimpleTreeView.OnGUI(new Rect(0, 0, position.width, position.height)); } // Add menu named "My Window" to the Window menu [MenuItem ("TreeView Examples/Simple Tree Window")] static void ShowWindow () { // Get existing open window or if none, make a new one: var window = GetWindow (); window.titleContent = new GUIContent ("My Window"); window.Show (); } }

Пример 2. TreeView с несколькими столбцами

В этом примере показан объект TreeView с несколькими столбцами, в котором используется класс MultiColumnHeader.

MultiColumnHeader поддерживает следующие функции: переименование элементов, множественный выбор, изменение порядка элементов и содержимого настраиваемых строк с использованием обычных элементов управления IMGUI (таких как ползунки и поля объектов), сортировка столбцов. , а также фильтрация и поиск строк.

В этом примере создается модель данных с использованием классов TreeElement и TreeModel. TreeView извлекает данные из этой «TreeModel». В этом примере были встроены классы TreeElement и TreeModel для демонстрации возможностей класса TreeView. Эти классы были включены в проект примеров TreeView (TreeViewExamples.zip). В примере также показано, как древовидная структура модели сериализуется в ScriptableObject и сохраняется в активе.

[Serializable] //The TreeElement data class is extended to hold extra data, which you can show and edit in the front-end TreeView. internal class MyTreeElement : TreeElement { public float floatValue1, floatValue2, floatValue3; public Material material; public string text = ""; public bool enabled = true; public MyTreeElement (string name, int depth, int id) : base (name, depth, id) { floatValue1 = Random.value; floatValue2 = Random.value; floatValue3 = Random.value; } }

The following ScriptableObject class ensures that data persists in an Asset when the tree is serialized.

[CreateAssetMenu (fileName = "TreeDataAsset", menuName = "Tree Asset", order = 1)] public class MyTreeAsset : ScriptableObject { [SerializeField] List m_TreeElements = new List (); internal List treeElements { get { return m_TreeElements; } set { m_TreeElements = value; } } }

Построение класса MultiColumnTreeView

В следующем примере показаны фрагменты класса MultiColumnTreeView, которые иллюстрируют, как достигается многоколоночный графический интерфейс. Полный исходный код можно найти в проекте примеров TreeView (TreeViewExamples.zip).

public MultiColumnTreeView (TreeViewState state, MultiColumnHeader multicolumnHeader, TreeModel model) : base (state, multicolumnHeader, model) { // Custom setup rowHeight = 20; columnIndexForTreeFoldouts = 2; showAlternatingRowBackgrounds = true; showBorder = true; customFoldoutYOffset = (kRowHeights - EditorGUIUtility.singleLineHeight) * 0.5f; extraSpaceBeforeIconAndLabel = kToggleWidth; multicolumnHeader.sortingChanged += OnSortingChanged; Reload(); }

Пользовательские изменения в приведенном выше примере кода вносят следующие коррективы:

  • rowHeight = 20: изменить высоту по умолчанию (которая основана на EditorGUIUtility.singleLineHeight's 16 баллов) до 20, чтобы добавить больше места для элементов управления графическим интерфейсом.

  • columnIndexForTreeFoldouts = 2: в этом примере раскрывающиеся стрелки отображаются в третьем столбце, поскольку для этого значения установлено значение 2 (см. изображение выше). Если это значение не изменить, развороты отображаются в первом столбце, поскольку по умолчанию столбец «columnIndexForTreeFoldouts» равен 0.

  • showAlternatingRowBackgrounds = true: включить чередование цветов фона строк, чтобы каждая строка была различна.

  • showBorder = true: отображает TreeView с полем вокруг него, чтобы отображалась тонкая рамка, отделяющая его от остального содержимого

  • customFoldoutYOffset = (kRowHeights - EditorGUIUtility.singleLineHeight) * 0,5f: центрировать складки по вертикали в строке — см. Настройка графического интерфейса пользователя ниже.

  • extraSpaceBeforeIconAndLabel = 20: сделайте пробел перед метками дерева, чтобы кнопка-переключатель отображалась.

  • multicolumnHeader.sortingChanged += OnSortingChanged: назначьте событию метод для обнаружения изменения сортировки в компоненте заголовка (при щелчке столбца заголовка), чтобы строки Изменение TreeView для отражения состояния сортировки.

Настройка графического интерфейса

Если используется обработка RowGUI по умолчанию, TreeView выглядит так же, как приведенный выше пример SimpleTreeView, только со складками и меткой. При использовании нескольких значений данных для каждого элемента необходимо переопределить метод RowGUI для визуализации этих значений.

protected override void RowGUI (RowGUIArgs args)

Следующий пример кода представляет собой структуру аргументов структуры RowGUIArgs.

protected struct RowGUIArgs { public TreeViewItem item; public string label; public Rect rowRect; public int row; public bool selected; public bool focused; public bool isRenaming; public int GetNumVisibleColumns () public int GetColumn (int visibleColumnIndex) public Rect GetCellRect (int visibleColumnIndex) }

Вы можете расширить TreeViewItem и добавить дополнительные пользовательские данные (которые создают класс, производный от TreeViewItem). Затем вы можете использовать эти пользовательские данные в обратном вызове RowGUI. Пример этого приведен ниже. См. раздел override void RowGUI — в этом примере входной элемент преобразуется в TreeViewItem.

Существует три метода, связанных с обработкой столбцов: GetNumVisibleColumns, GetColumn и GetCellRect. Вы можете вызывать их только тогда, когда TreeView создан с MultiColumnHeader, иначе будет выдано исключение.

protected override void RowGUI (RowGUIArgs args) { var item = (TreeViewItem) args.item; for (int i = 0; i < args.GetNumVisibleColumns (); ++i) { CellGUI(args.GetCellRect(i), item, (MyColumns)args.GetColumn(i), ref args); } } void CellGUI (Rect cellRect, TreeViewItem item, MyColumns column, ref RowGUIArgs args) { // Center the cell rect vertically using EditorGUIUtility.singleLineHeight. // This makes it easier to place controls and icons in the cells. CenterRectUsingSingleLineHeight(ref cellRect); switch (column) { case MyColumns.Icon1: // Draw custom texture GUI.DrawTexture(cellRect, s_TestIcons[GetIcon1Index(item)], ScaleMode.ScaleToFit); break; case MyColumns.Icon2: //Draw custom texture GUI.DrawTexture(cellRect, s_TestIcons[GetIcon2Index(item)], ScaleMode.ScaleToFit); break; case MyColumns.Name: // Make a toggle button to the left of the label text Rect toggleRect = cellRect; toggleRect.x += GetContentIndent(item); toggleRect.width = kToggleWidth; if (toggleRect.xMax < cellRect.xMax) item.data.enabled = EditorGUI.Toggle(toggleRect, item.data.enabled); // Default icon and label args.rowRect = cellRect; base.RowGUI(args); break; case MyColumns.Value1: // Show a Slider control for value 1 item.data.floatValue1 = EditorGUI.Slider(cellRect, GUIContent.none, item.data.floatValue1, 0f, 1f); break; case MyColumns.Value2: // Show an ObjectField for materials item.data.material = (Material)EditorGUI.ObjectField(cellRect, GUIContent.none, item.data.material, typeof(Material), false); break; case MyColumns.Value3: // Show a TextField for the data text string item.data.text = GUI.TextField(cellRect, item.data.text); break; } }

Часто задаваемые вопросы о дереве

В: В моем подклассе TreeView есть функции BuildRoot и RowGUI. Вызывается ли RowGUI для каждого TreeViewItem, добавленного в функцию сборки, или только для элементов, видимых на экране в прокрутке посмотреть?

A: RowGUI вызывается только для элементов, видимых на экране. Например, если у вас есть 10 000 элементов, только для 20 видимых элементов на экране вызывается их RowGUI.

В: Могу ли я получить индексы строк, которые видны на экране?

О: Да. Используйте метод GetFirstAndLastVisibleRows.

В: Могу ли я получить список строк, созданных в BuildRows?

О: Да. Используйте метод GetRows.

В: Обязательно ли для любой из переопределенных функций вызывать base.Method?

A: Только если у метода есть поведение по умолчанию, которое вы хотите расширить.

В: Я просто хочу создать список элементов (не дерево). Нужно ли создавать корень?

A: Да, у вас всегда должен быть рут. Вы можете создать корневой элемент и установить root.children = rows для быстрой настройки.

В: Я добавил переключатель в свою строку. Почему выделение не переходит к этой строке, когда я нажимаю на нее?

A: По умолчанию строка выбирается только в том случае, если нажатая мышь не занята содержимым строки. Здесь ваш Toggle использует событие. Чтобы исправить это, используйте метод SelectionClick перед вызовом кнопки переключения.

В: Существуют ли методы, которые можно использовать до или после вызова всех методов RowGUI?

О: Да. См. документацию по API в BeforeRowsGUI и AfterRowsGUI.

В: Есть ли простой способ вернуть ключевой фокус в TreeView из API? Если я выберу FloatField в своей строке, выделение строки станет серым. Как сделать его снова синим?

A: Синий цвет указывает, какая строка в данный момент находится в фокусе. Поскольку FloatField имеет фокус, TreeView теряет фокус, так что это предполагаемое поведение. При необходимости задайте GUIUtility.keyboardControl = treeViewControlID.

В: Как преобразовать id в TreeViewItem?

О. Используйте либо FindItem, либо FindRows.

В: Как получить обратный вызов, когда пользователь изменяет свой выбор в TreeView?

A: Переопределите метод SelectionChanged (другие полезные обратные вызовы: DoubleClickedItem и ContextClickedItem).

Вы можете отблагодарить автора, за перевод документации на русский язык. ₽ Спасибо
Руководство Unity 2021.3